Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

新增基于状态机模型的规则模块 #160

Closed
wants to merge 7 commits into from

Conversation

PluieM
Copy link
Contributor

@PluieM PluieM commented Jun 19, 2024

主要有两点更新
1、按照 #156@Gaojianli 提供的思路 新增基于状态机模型的规则模块,并基于这个模块重构了订阅规则模块和PeerID黑名单模块
2、#155 拓展规则订阅支持的规则类型,现在支持如下几种类型IP/PEER_ID_CONTAINS/PEER_ID_STARTS_WITH/CLIENT_NAME_CONTAINS/CLIENT_NAME_STARTS_WITH

Summary by CodeRabbit

  • New Features

    • Implemented a state machine-based ban logic for enhanced peer management.
    • Added rule-based blocking functionality using AbstractRuleBlocker and related classes.
    • Introduced MatchEvents, MatchResultDetail, PeerMatchContext, PeerState, and RuleBlocker for comprehensive rule matching.
    • Added PeerIdBlocker for blocking peers based on IDs.
    • Enhanced configuration management with subModuleUpdate() in ProfileUpdateScript.
  • Bug Fixes

    • Improved rule update and loading mechanisms for better reliability.
  • Refactor

    • Renamed classes and fields to better align with new rule management logic.
    • Updated logging and error handling for improved clarity and troubleshooting.
  • Style

    • Updated various strings in Lang.java for improved localization and clarity.

PluieM added 2 commits June 19, 2024 15:31
2、将规则订阅和Peer黑名单的匹配模块基于新的规则规则模块进行重构
3、微调规则订阅模块方便后续加入更多订阅规则的匹配类型
Copy link
Contributor

coderabbitai bot commented Jun 19, 2024

Walkthrough

The changes introduced a new state machine-based banning mechanism by adding multiple classes and modifying existing ones to manage peer connections and bans more efficiently. Key additions include constructing state machines, updating peer conditions, and enhanced rule matching. The updated logic significantly improves how peer bans are managed, focusing on modular rule handling and better configuration.

Changes

File Path Change Summary
pom.xml Added a new dependency for state machine functionality.
src/main/java/com/ghostchu/.../PeerBanHelperServer.java Added state machine logic, new fields, and refactored existing methods for better peer management.
src/main/java/com/ghostchu/.../config/ProfileUpdateScript.java Introduced and modified methods for updating module configuration settings.
src/main/java/com/ghostchu/.../database/DatabaseHelper.java Renamed IPBanRuleUpdateType to RuleUpdateType affecting method signatures and usage.
src/main/java/com/ghostchu/.../database/RuleSubLog.java Updated to reflect the renaming of rule update types and affected fields.
src/main/java/com/ghostchu/.../module/AbstractRuleBlocker.java Introduced an abstract class with methods for rule blocking and state machine management.
src/main/java/com/ghostchu/.../module/MatchEvents.java Added enum to define various match events for state transitions.
src/main/java/com/ghostchu/.../module/MatchResultDetail.java Added new class for capturing match result details with context and reasons.
src/main/java/com/ghostchu/.../module/PeerMatchContext.java Added new class encapsulating peer match operations with state machine.
src/main/java/com/ghostchu/.../module/PeerState.java Added enum defining various states of a peer in the state machine.
src/main/java/com/ghostchu/.../module/RuleBlocker.java Added interface defining methods for rule-based blocking and state machine interactions.
src/main/java/com/ghostchu/.../impl/rule/PeerIdBlocker.java Implemented class for blocking peers based on IDs with configuration parsing and rule evaluations.
src/main/java/com/ghostchu/.../impl/rule/RuleSubBlocker.java Renamed and refactored old class to improve rule handling and added new matcher types.
src/main/java/com/ghostchu/.../impl/webapi/RuleSubController.java Refactored API module methods and updated to reflect renamed classes and types.
src/main/java/com/ghostchu/.../text/Lang.java Updated multiple strings related to subscription rules and added new entries.
src/main/java/com/ghostchu/.../util/rule/RuleMatcher.java Introduced new utility for rule matching.

Sequence Diagrams

New State Machine-Based Peer Ban Workflow

Loading
sequenceDiagram
    actor Admin
    participant PeerBanHelperServer
    participant RuleBlocker
    participant StateMachine
    participant PeerMatchRecord

    Admin ->> PeerBanHelperServer: Initialize Server
    PeerBanHelperServer ->> RuleBlocker: registerModules()
    RuleBlocker ->> StateMachine: Initialize StateMachine
    RuleBlocker ->> PeerMatchRecord: Create matchRecords map
    
    PeerMatchRecord ->> StateMachine: Evaluate match with rules
    StateMachine ->> PeerMatchRecord: Update state based on events

    RuleBlocker ->> PeerBanHelperServer: Update peer state
    PeerBanHelperServer ->> Admin: Inform about ban wave

Poem

In the land of code and peers,
Where modules and state machines steer,
A rabbit hops through lines of might,
Banning those who flee in fright.
Rules are strict, yet fair in kind,
Connection safe, with peace of mind.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
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>.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @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.

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 as 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 resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration 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
Contributor

@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: 16

Outside diff range and nitpick comments (5)
src/main/java/com/ghostchu/peerbanhelper/module/AbstractRuleBlocker.java (1)

3-17: Ensure proper documentation for public members and methods in AbstractRuleBlocker.

Adding Javadoc comments to public members and methods would enhance maintainability and understandability, especially for abstract classes intended to be extended by others.

src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/RuleSubController.java (2)

106-106: Improve error messaging to include details about what parameter was incorrect.

ctx.json(new SlimMsg(false, Lang.SUB_RULE_CHECK_INTERVAL_WRONG_PARAM + ": checkInterval"));

129-131: Include more specific error details in the log message to aid in debugging.

log.error(Lang.SUB_RULE_LOG_QUERY_ERROR + " for ruleId: " + ruleId, e);
src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java (2)

Line range hint 381-456: The method banWave has been significantly modified to incorporate state machine logic for ban management. It's important to ensure that the logic here is thoroughly tested, especially since it deals with concurrency and state transitions which are prone to errors. Consider adding more detailed logs or comments explaining each state transition for future maintainability.

+ // Consider adding more detailed logs or comments explaining each state transition for future maintainability.

Line range hint 727-757: The banPeer method has been refactored to support the new rule-based blocking logic. It is crucial to ensure that all parameters are correctly passed and that the ban logic is accurately implemented. Additionally, consider optimizing the DNS reverse lookup to avoid potential performance bottlenecks.

+ // Consider optimizing the DNS reverse lookup to avoid potential performance bottlenecks.
Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 164f445 and b0cce39.

Files selected for processing (22)
  • pom.xml (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java (10 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/config/ProfileUpdateScript.java (3 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/database/DatabaseHelper.java (3 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/database/RuleSubLog.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/AbstractRuleBlocker.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/MatchEvents.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/MatchResultDetail.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/PeerMatchRecord.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/PeerState.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/RuleBlocker.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/RuleUpdateType.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/PeerIdBlocker.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/RuleSubBlocker.java (7 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/RuleSubController.java (14 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/text/Lang.java (3 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/RuleMatcher.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/RuleType.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/matcher/IPMatcher.java (2 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/matcher/PrefixMatcher.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/matcher/SubStrMatcher.java (1 hunks)
  • src/main/resources/profile.yml (3 hunks)
Files skipped from review due to trivial changes (5)
  • pom.xml
  • src/main/java/com/ghostchu/peerbanhelper/module/MatchEvents.java
  • src/main/java/com/ghostchu/peerbanhelper/module/PeerState.java
  • src/main/java/com/ghostchu/peerbanhelper/module/RuleUpdateType.java
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/RuleType.java
Additional comments not posted (34)
src/main/java/com/ghostchu/peerbanhelper/module/MatchResultDetail.java (1)

3-4: The MatchResultDetail record is well-defined and appropriately encapsulates the result details of a match operation.

src/main/java/com/ghostchu/peerbanhelper/database/RuleSubLog.java (1)

3-9: The refactoring in RuleSubLog to use RuleUpdateType aligns with the broader support for different rule types as stated in the PR objectives.

src/main/java/com/ghostchu/peerbanhelper/module/PeerMatchRecord.java (1)

10-21: The PeerMatchRecord class is well-defined, making effective use of Lombok annotations to simplify data class boilerplate. It appropriately encapsulates peer-related data along with match results.

src/main/java/com/ghostchu/peerbanhelper/util/rule/RuleMatcher.java (1)

9-33: The RuleMatcher class is effectively designed as an abstract base for specific rule matchers. It uses immutability and encapsulation well, aligning with good OOP practices and the needs of a rule-based system.
[APROVED]

src/main/java/com/ghostchu/peerbanhelper/module/AbstractRuleBlocker.java (1)

16-16: Verify the thread safety of StateMachine usage.

src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/PeerIdBlocker.java (1)

45-49: Ensure thread safety for web API endpoint registration.

src/main/java/com/ghostchu/peerbanhelper/util/rule/matcher/IPMatcher.java (3)

6-7: Import of RuleMatcher and RuleType is aligned with the changes to support new rule types.


22-29: The IPMatcher constructor properly initializes with the RuleType.IP, ensuring that the matcher is correctly categorized.


69-69: The matcherIdentifier method now returns a unique identifier for the IPMatcher, which is good for distinguishing this matcher in logs and debug output.

src/main/java/com/ghostchu/peerbanhelper/module/RuleBlocker.java (2)

67-74: The getServer and getLogger methods provide essential components for the rule blocker functionality. Ensuring these are exposed in the interface allows for better modularity and testing.


81-109: The methods getStateMachine, shouldBanPeer, and triggerEvent are crucial for the operation of rule-based blocking. The implementation of triggerEvent particularly ensures that the state machine events are fired correctly, which is central to the functionality of this module.

src/main/resources/profile.yml (2)

9-9: Introduction of disconnect-duration in the configuration aligns with the new features related to managing disconnect timeouts. This is a necessary addition for the enhanced functionality.


Line range hint 167-178: The configuration for rule-sub-blockers is set correctly according to the new module requirements. However, ensure that the URL provided is valid and accessible.

Verification successful

The URL "https://raw.githubusercontent.com/PBH-BTN/BTN-Collected-Rules/main/dt_torrent.txt" is accessible as confirmed by the script output.

  • The URL is accessible.
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Check if the URL is accessible
if curl --output /dev/null --silent --head --fail "https://raw.githubusercontent.com/PBH-BTN/BTN-Collected-Rules/main/dt_torrent.txt"; then
  echo "URL is accessible."
else
  echo "URL is not accessible."
fi

Length of output: 177

src/main/java/com/ghostchu/peerbanhelper/config/ProfileUpdateScript.java (1)

22-29: The subModuleUpdate method handles the transition of configuration from ip-address-blocker-rules to rule-sub-blockers effectively. This is crucial for the migration to the new rule system.

src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/RuleSubController.java (1)

154-154: Ensure consistent error handling and user feedback across all API endpoints.

Also applies to: 158-158, 175-175, 181-181, 206-206, 230-230, 237-237, 243-243, 251-251, 280-280

src/main/java/com/ghostchu/peerbanhelper/text/Lang.java (3)

24-24: Renamed string constant to reflect the new rule subscription system.


172-202: All these changes are related to renaming string constants to align with the new rule subscription system. This is consistent with the PR's objective of refactoring rule modules and expanding rule types.


215-216: Added new string constants for rule module operations, enhancing traceability and debugging capabilities.

src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/RuleSubBlocker.java (11)

8-20: Import statements have been added for new classes that are part of the rule system overhaul. This includes matchers for different rule types and utilities for rule handling.


31-31: Added import for Logger, likely used for logging within this class.


42-42: Imported CountDownLatch and related concurrency utilities, indicating the use of asynchronous programming patterns within this class.


50-50: The class now extends AbstractRuleBlocker, aligning with the new architectural design of the rule system.


54-54: Added a field for managing the checking interval and its corresponding getter. The constructor has been modified to accept a DatabaseHelper object, integrating database operations directly into rule handling.

Also applies to: 58-58


64-64: Standard methods for module management such as getName, getConfigName, and getLogger. These align with the expected modular design patterns.

Also applies to: 69-69, 74-74


80-80: Methods onEnable and init setup the rule checking interval and load initial configurations. The use of a state machine is evident here, which is central to the new rule handling logic.

Also applies to: 89-98


106-113: The reloadConfig method ensures dynamic updating of the configuration without needing a system restart, enhancing the flexibility of the rule handling system.


115-141: The shouldBanPeer method implements the logic to determine if a peer should be banned based on the loaded rules. It uses asynchronous programming patterns to evaluate all rules concurrently, which should improve performance on large rule sets.


Line range hint 149-279: The updateRule method handles the logic for updating rules from a remote source or local cache. It includes error handling, logging, and database interactions to log rule updates. This method is central to the functionality of the rule module, ensuring rules are current and correctly applied.


284-300: Utility methods fileToLines and fileToIPList are used to parse rule files into usable data structures. These methods are well-implemented with error handling and logging, supporting the main functionality of rule parsing.

src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java (5)

74-74: The addition of disconnectTimeout is well-aligned with the PR's objectives to improve ban logic using a state machine. Ensure this value is appropriately documented and validated.


100-100: Changing moduleManager to final is a good practice as it ensures immutability where possible, which can help prevent accidental reassignments and bugs related to concurrency.


108-108: The matchRecords map is a crucial component for the new state machine logic. It's important to ensure thread safety, which is achieved here by using ConcurrentHashMap. This is particularly vital given the asynchronous nature of the operations that modify this map.


114-114: Proper initialization of disconnectTimeout from the configuration file is done here. It's essential to handle potential misconfigurations gracefully, such as providing defaults or logging warnings if the configuration is missing or invalid.


584-593: The registration of modules has been updated to include the new RuleSubBlocker. This change should be reflected across all configurations and documentation to ensure that users are aware of the new capabilities and how to configure them.

Comment on lines 474 to 475
} catch (InterruptedException e) {
throw new RuntimeException(e);
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 19, 2024

Choose a reason for hiding this comment

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

Using a RuntimeException to handle InterruptedException is generally not recommended. It's better to either re-interrupt the thread or handle the interruption more gracefully, depending on the desired application behavior.

- throw new RuntimeException(e);
+ Thread.currentThread().interrupt(); // Restore the interrupted status
// or handle the interruption more appropriately depending on the context
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Restore the interrupted status
// or handle the interruption more appropriately depending on the context

Copy link
Collaborator

Choose a reason for hiding this comment

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

需要应用建议的更改

Copy link
Contributor

Choose a reason for hiding this comment

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

@Ghost-chu, I've noted your decision to apply the suggested changes to handle InterruptedException more appropriately. Please ensure to update the exception handling in your development environment as discussed. If you need any more assistance or further modifications, feel free to ask!

Comment on lines 32 to 36
@Override
public void setData(String ruleName, Object... ruleData) {
this.ruleName = ruleName;
this.ips = ips;
this.subnets = subnets;
this.ips = ruleData.length > 0 ? (List<IPAddress>) ruleData[0] : List.of();
this.subnets = ruleData.length > 1 ? (List<IPAddress>) ruleData[1] : List.of();
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 19, 2024

Choose a reason for hiding this comment

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

Ensure type safety and potential ClassCastException when casting ruleData to List<IPAddress>.

Consider adding type checks before casting to avoid runtime exceptions:

if (ruleData.length > 0 && ruleData[0] instanceof List) {
    this.ips = (List<IPAddress>) ruleData[0];
} else {
    this.ips = List.of();
}
// Repeat for subnets

Copy link
Collaborator

Choose a reason for hiding this comment

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

重构为泛型,以避免使用不安全的强制类型转换。

Copy link
Contributor

Choose a reason for hiding this comment

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

@Ghost-chu, 您的建议非常合理。使用泛型可以在编译时检查类型安全,避免运行时的类型转换错误。这里是按照您的建议重构的代码片段:

public class IPMatcher extends RuleMatcher<List<IPAddress>> {

    private List<IPAddress> subnets;
    private List<IPAddress> ips;
    private BloomFilter<String> bloomFilter;

    public IPMatcher(String ruleId, String ruleName, List<IPAddress> ruleData) {
        super(RuleType.IP, ruleId, ruleName, ruleData);
        setData(ruleName, ruleData);
    }

    @Override
    public void setData(String ruleName, List<IPAddress> ruleData) {
        this.ruleName = ruleName;
        this.ips = ruleData != null ? ruleData : List.of();
        this.subnets = ruleData != null ? ruleData : List.of();
        bloomFilter = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), ips.size(), 0.01);
        ips.forEach(ip -> bloomFilter.put(ip.toString()));
    }

    @Override
    public @NotNull MatchResult match0(@NotNull String content) {
        IPAddress pa = IPAddressUtil.getIPAddress(content);
        if (pa.isIPv4Convertible()) {
            pa = pa.toIPv4();
        }
        final IPAddress ip = pa;
        if (bloomFilter.mightContain(content)) {
            if (ips.stream().anyMatch(ele -> ele.isIPv4Convertible() == ip.isIPv4Convertible() && ele.equals(ip))) {
                return MatchResult.TRUE;
            }
        }
        if (subnets.stream().anyMatch(subnet -> subnet.contains(ip))) {
            return MatchResult.TRUE;
        }
        return MatchResult.DEFAULT;
    }

    @Override
    public @NotNull String matcherName() {
        return Lang.RULE_MATCHER_SUB_RULE;
    }

    @Override
    public String matcherIdentifier() {
        return "peerbanhelper:ipmatcher";
    }
}

这段代码中,IPMatcher 类现在接受一个具体的 List<IPAddress> 类型作为参数,这样可以在编译时确保类型安全。如果有其他需要调整的地方,请告诉我!

Comment on lines 25 to 28
@Override
public void setData(String ruleName, Object... ruleData) {
this.ruleName = ruleName;
this.subStrs = ruleData.length > 0 ? (List<String>) ruleData[0] : List.of();
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 19, 2024

Choose a reason for hiding this comment

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

Refactor setData to handle potential ClassCastException.

When casting ruleData[0] to List<String>, ensure it is safely cast to avoid runtime exceptions.

  @Override
  public void setData(String ruleName, Object... ruleData) {
      this.ruleName = ruleName;
-     this.subStrs = ruleData.length > 0 ? (List<String>) ruleData[0] : List.of();
+     this.subStrs = (ruleData.length > 0 && ruleData[0] instanceof List) ? (List<String>) ruleData[0] : List.of();
  }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Override
public void setData(String ruleName, Object... ruleData) {
this.ruleName = ruleName;
this.subStrs = ruleData.length > 0 ? (List<String>) ruleData[0] : List.of();
@Override
public void setData(String ruleName, Object... ruleData) {
this.ruleName = ruleName;
this.subStrs = (ruleData.length > 0 && ruleData[0] instanceof List) ? (List<String>) ruleData[0] : List.of();

Copy link
Collaborator

Choose a reason for hiding this comment

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

重构为泛型,以避免使用不安全的强制类型转换。

Copy link
Contributor

Choose a reason for hiding this comment

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

@Ghost-chu, 您提出的使用泛型来避免不安全的类型转换是一个很好的建议。这样可以在编译时就确保类型安全,减少运行时的错误。下面是根据您的建议重构的代码:

package com.ghostchu.peerbanhelper.util.rule.matcher;

import com.ghostchu.peerbanhelper.text.Lang;
import com.ghostchu.peerbanhelper.util.rule.MatchResult;
import com.ghostchu.peerbanhelper.util.rule.RuleMatcher;
import com.ghostchu.peerbanhelper.util.rule.RuleType;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;

import java.util.List;

@Slf4j
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SubStrMatcher<T extends List<String>> extends RuleMatcher {

    private T subStrs;

    public SubStrMatcher(RuleType ruleType, String ruleId, String ruleName, Object... ruleData) {
        super(ruleType, ruleId, ruleName, ruleData);
    }

    @Override
    public void setData(String ruleName, T ruleData) {
        this.ruleName = ruleName;
        this.subStrs = ruleData != null ? ruleData : List.of();
    }
}

在这个版本中,SubStrMatcher 类现在是泛型的,它期望其数据是 List<String> 类型。这样,任何不符合此类型的数据都会在编译时被捕获,而不是在运行时抛出 ClassCastException。如果有其他问题或需要进一步的调整,请告诉我!

Comment on lines 33 to 34
if (subStrs.parallelStream().anyMatch(content::contains)) {
return MatchResult.TRUE;
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 19, 2024

Choose a reason for hiding this comment

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

Optimize parallel stream usage in match0.

Using parallelStream for potentially small collections might not be efficient due to the overhead of thread management. Consider conditions under which parallelism is beneficial.

  @Override
  public @NotNull MatchResult match0(@NotNull String content) {
-     if (subStrs.parallelStream().anyMatch(content::contains)) {
+     if (subStrs.stream().anyMatch(content::contains)) {
          return MatchResult.TRUE;
      }
      return MatchResult.DEFAULT;
  }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (subStrs.parallelStream().anyMatch(content::contains)) {
return MatchResult.TRUE;
@Override
public @NotNull MatchResult match0(@NotNull String content) {
if (subStrs.stream().anyMatch(content::contains)) {
return MatchResult.TRUE;
}
return MatchResult.DEFAULT;
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

避免使用 parallelStream() 除非有十分耗时且大量的操作,否则上下文切换和线程调度开销反而会使得性能变差。

stream 本身也比较费时,JVM 并不会对 stream 进行太多编译优化,对于十分简单的操作,依然建议使用传统 for 循环。

Copy link
Contributor

Choose a reason for hiding this comment

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

@Ghost-chu, 您的建议非常中肯。对于 SubStrMatcher 类中的 match0 方法,确实应该优先考虑性能和简洁性。考虑到 subStrs 可能只包含少量元素,使用传统的 for 循环将是更优的选择,这样可以避免 stream 引入的额外开销。以下是修改后的代码示例:

@Override
public @NotNull MatchResult match0(@NotNull String content) {
    for (String subStr : subStrs) {
        if (content.contains(subStr)) {
            return MatchResult.TRUE;
        }
    }
    return MatchResult.DEFAULT;
}

这段代码直接遍历 subStrs 列表,并检查内容中是否包含任何子字符串。如果找到匹配项,立即返回 MatchResult.TRUE;如果遍历完列表没有找到,返回 MatchResult.DEFAULT。这种方式比使用 stream 更直接且效率更高。

请您查看上述修改是否符合预期,如果有其他建议或问题,欢迎继续讨论。

Comment on lines 33 to 34
if (prefixes.parallelStream().anyMatch(content::startsWith)) {
return MatchResult.TRUE;
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 19, 2024

Choose a reason for hiding this comment

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

Optimize parallel stream usage in match0.

Using parallelStream for potentially small collections might not be efficient due to the overhead of thread management. Consider conditions under which parallelism is beneficial.

  @Override
  public @NotNull MatchResult match0(@NotNull String content) {
-     if (prefixes.parallelStream().anyMatch(content::startsWith)) {
+     if (prefixes.stream().anyMatch(content::startsWith)) {
          return MatchResult.TRUE;
      }
      return MatchResult.DEFAULT;
  }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (prefixes.parallelStream().anyMatch(content::startsWith)) {
return MatchResult.TRUE;
if (prefixes.stream().anyMatch(content::startsWith)) {
return MatchResult.TRUE;

Copy link
Collaborator

Choose a reason for hiding this comment

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

避免使用 parallelStream() 除非有十分耗时且大量的操作,否则上下文切换和线程调度开销反而会使得性能变差。

stream 本身也比较费时,JVM 并不会对 stream 进行太多编译优化,对于十分简单的操作,依然建议使用传统 for 循环。

Copy link
Contributor

Choose a reason for hiding this comment

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

@Ghost-chu, 您的建议非常中肯!确实,对于简单的字符串前缀匹配操作,使用 parallelStream 可能会由于线程管理和上下文切换的开销而导致性能不佳。我同意您的观点,对于这种情况,传统的 for 循环可能会更加高效。

这里是按照您的建议修改后的代码:

@Override
public @NotNull MatchResult match0(@NotNull String content) {
    for (String prefix : prefixes) {
        if (content.startsWith(prefix)) {
            return MatchResult.TRUE;
        }
    }
    return MatchResult.DEFAULT;
}

这种方式避免了使用 stream 带来的额外开销,应该能够提升方法的执行效率。如果还有其他需要讨论或优化的地方,请随时告诉我!


Learnings added
User: Ghost-chu
PR: PBH-BTN/PeerBanHelper#160
File: src/main/java/com/ghostchu/peerbanhelper/util/rule/matcher/PrefixMatcher.java:33-34
Timestamp: 2024-06-20T05:54:47.669Z
Learning: Avoid using parallelStream() for simple operations due to the overhead of thread management and context switching. Traditional for-loops are recommended for simple string matching tasks.

Note: Learnings are effective only in the context of specific code segments. To apply general coding guidelines, please configure review instructions.

Comment on lines 25 to 28
@Override
public void setData(String ruleName, Object... ruleData) {
this.ruleName = ruleName;
this.prefixes = ruleData.length > 0 ? (List<String>) ruleData[0] : List.of();
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 19, 2024

Choose a reason for hiding this comment

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

Refactor setData to handle potential ClassCastException.

When casting ruleData[0] to List<String>, ensure it is safely cast to avoid runtime exceptions.

  @Override
  public void setData(String ruleName, Object... ruleData) {
      this.ruleName = ruleName;
-     this.prefixes = ruleData.length > 0 ? (List<String>) ruleData[0] : List.of();
+     this.prefixes = (ruleData.length > 0 && ruleData[0] instanceof List) ? (List<String>) ruleData[0] : List.of();
  }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Override
public void setData(String ruleName, Object... ruleData) {
this.ruleName = ruleName;
this.prefixes = ruleData.length > 0 ? (List<String>) ruleData[0] : List.of();
@Override
public void setData(String ruleName, Object... ruleData) {
this.ruleName = ruleName;
this.prefixes = (ruleData.length > 0 && ruleData[0] instanceof List) ? (List<String>) ruleData[0] : List.of();

Copy link
Collaborator

Choose a reason for hiding this comment

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

重构为泛型,以避免使用不安全的强制类型转换。

Copy link
Contributor

Choose a reason for hiding this comment

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

@Ghost-chu, 您的建议非常合理。通过使用泛型,我们可以在编译时确保类型安全,避免运行时的类型转换错误。以下是根据您的建议重构的 setData 方法:

@Override
public void setData(String ruleName, List<String> prefixes) {
    this.ruleName = ruleName;
    this.prefixes = prefixes != null ? prefixes : List.of();
}

这样修改后,PrefixMatcher 类的使用者需要在调用 setData 方法时提供 List<String> 类型的参数,这确保了类型的安全性和一致性。如果有其他相关的类或方法也需要调整,请告知,我可以帮助进一步修改。

Copy link
Contributor

@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: 2

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between b0cce39 and f05b6bd.

Files selected for processing (2)
  • src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/RuleSubBlocker.java (7 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/RuleMatcher.java (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/RuleMatcher.java
Additional comments not posted (6)
src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/RuleSubBlocker.java (6)

8-10: Imports for AbstractRuleBlocker, PeerMatchRecord, and RuleUpdateType have been added. Ensure that these classes/interfaces are correctly implemented and used in the system as expected.


16-20: Addition of imports for various matchers (IPMatcher, PrefixMatcher, SubStrMatcher) aligns with the expanded rule types mentioned in the PR. Ensure these classes are well-implemented and tested.


50-58: The RuleSubBlocker class extends AbstractRuleBlocker. This design promotes reusability and modularity in handling rule-based actions. Confirm that all necessary methods from AbstractRuleBlocker are appropriately overridden.


64-70: The methods getName() and getConfigName() provide clear identifiers for the module, which is good practice for clarity and maintainability.


292-300: The utility method fileToLines is well-implemented for reading files into a list. Ensure that it is used in a context where exception handling is adequately managed.


Line range hint 149-269: The updateRule method handles rule updates with remote fetching and local caching. It's a critical method with many branching paths and external interactions. Ensure thorough testing, particularly for error handling and edge cases.

Consider breaking down this method into smaller, more manageable functions to improve readability and maintainability.

Verification successful

The examination of the updateRule method's usage in RuleSubController and BtnAbilityRules files reveals the following:

  • In RuleSubController, the updateRule method is called with proper error handling and logging. For instance, if the ConfigurationSection is null, it returns an error message. Additionally, the results of updateRule are checked, and appropriate actions are taken based on the success or failure of the operation.
  • In BtnAbilityRules, the updateRule method is scheduled to run at fixed intervals. However, the actual error handling or logging within the updateRule method itself isn't shown here, but it's implied that updateRule handles its own exceptions and logs errors internally.

Given this context, the updateRule method appears to be used correctly with adequate error handling and logging.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify the `updateRule` method's interaction with external services and file handling.

# Test: Search for the method usage. Expect: Proper error handling and logging.
rg --type java $'updateRule'

Length of output: 1185



Script:

#!/bin/bash
# Extract lines around updateRule method usage in RuleSubController.java
rg -A 5 -B 5 'updateRule' src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/RuleSubController.java

# Extract lines around updateRule method usage in BtnAbilityRules.java
rg -A 5 -B 5 'updateRule' src/main/java/com/ghostchu/peerbanhelper/btn/ability/BtnAbilityRules.java

Length of output: 2260

}

@Override
public void onEnable() {
stateMachine = ruleSmBuilder().build(getConfigName());
Copy link
Contributor

Choose a reason for hiding this comment

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

Initialization logic in onEnable() and init() methods is comprehensive. However, consider adding error handling for potential exceptions during configuration loading and rule updates.

+ try {
  stateMachine = ruleSmBuilder().build(getConfigName());
  ConfigurationSection config = getConfig();
  checkInterval = config.getLong("check-interval", checkInterval);
  scheduledExecutorService = Executors.newScheduledThreadPool(1);
  scheduledExecutorService.scheduleAtFixedRate(this::reloadConfig, 0, checkInterval, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+     log.error("Initialization error", e);
+ }

Also applies to: 89-98

Comment on lines 116 to 141
public CheckResult shouldBanPeer(PeerMatchRecord ctx) {
AtomicReference<CheckResult> result = new AtomicReference<>(new CheckResult(false, null, null));
CountDownLatch latch = new CountDownLatch(rules.size());
try (var service = Executors.newVirtualThreadPerTaskExecutor()) {
rules.forEach(matcher -> service.submit(() -> {
String matchStr;
Object type = matcher.metadata().get("type");
if (type == RuleType.PEER_ID_STARTS_WITH || type == RuleType.PEER_ID_CONTAINS) {
matchStr = ctx.getPeer().getPeerId();
} else if (type == RuleType.CLIENT_NAME_STARTS_WITH || type == RuleType.CLIENT_NAME_CONTAINS) {
matchStr = ctx.getPeer().getClientName();
} else {
matchStr = ctx.getPeer().getAddress().getIp();
}
if (matcher.match(matchStr) == MatchResult.TRUE) {
result.set(new CheckResult(true, matcher.metadata().get("rule").toString(), String.format(Lang.MODULE_IBL_MATCH_SUB_RULE, matcher.metadata().get("rule").toString())));
}
latch.countDown();
}));
}
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return result.get();
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 19, 2024

Choose a reason for hiding this comment

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

The method shouldBanPeer uses a concurrent approach to evaluate rules, which is efficient. However, the use of AtomicReference and CountDownLatch adds complexity. Consider simplifying this logic or ensuring that it is well-documented for maintainability.

Copy link
Collaborator

Choose a reason for hiding this comment

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

不需要使用 CountDownLatch,在 try-with-resource 中使用 Executors.newVirtualThreadPerTaskExecutor() 时,离开 try-with-resource 块时会调用 close 方法,其会调用 shutdown 方法。shutdown 方法将等待所有任务完成。

Copy link
Contributor

Choose a reason for hiding this comment

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

@Ghost-chu, you're correct about the Executors.newVirtualThreadPerTaskExecutor() behavior in a try-with-resources block. Removing the CountDownLatch can indeed simplify the code by relying on the executor's automatic shutdown to wait for all tasks to complete.

However, it's essential to ensure that the results of all rule checks are correctly aggregated before making a decision on whether to ban a peer. The existing AtomicReference and CountDownLatch mechanism explicitly handles this aggregation. If we remove CountDownLatch, we'll need to ensure that an alternative method for result aggregation is in place to maintain the correctness of the shouldBanPeer method.

Would you like to proceed with refactoring this part to remove CountDownLatch and adjust the result aggregation accordingly? I can help draft the changes if needed.


Learnings added
User: Ghost-chu
PR: PBH-BTN/PeerBanHelper#160
File: src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/RuleSubBlocker.java:116-141
Timestamp: 2024-06-20T05:54:49.474Z
Learning: The `Executors.newVirtualThreadPerTaskExecutor()` used in a try-with-resources statement automatically calls `shutdown()` upon exiting the block, which waits for all tasks to complete.

Note: Learnings are effective only in the context of specific code segments. To apply general coding guidelines, please configure review instructions.

@Gaojianli
Copy link
Member

Gaojianli commented Jun 19, 2024 via email

@Ghost-chu
Copy link
Collaborator

PBH 对于 ClientName、PeerID 和 IP 匹配(本地)都有缓存机制,检查只会执行一次,我在考虑这个状态机是否放在其它地方会好一点。

@Gaojianli
Copy link
Member

Gaojianli commented Jun 20, 2024 via email

Comment on lines 33 to 34
if (subStrs.parallelStream().anyMatch(content::contains)) {
return MatchResult.TRUE;
Copy link
Collaborator

Choose a reason for hiding this comment

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

避免使用 parallelStream() 除非有十分耗时且大量的操作,否则上下文切换和线程调度开销反而会使得性能变差。

stream 本身也比较费时,JVM 并不会对 stream 进行太多编译优化,对于十分简单的操作,依然建议使用传统 for 循环。

Comment on lines 33 to 34
if (prefixes.parallelStream().anyMatch(content::startsWith)) {
return MatchResult.TRUE;
Copy link
Collaborator

Choose a reason for hiding this comment

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

避免使用 parallelStream() 除非有十分耗时且大量的操作,否则上下文切换和线程调度开销反而会使得性能变差。

stream 本身也比较费时,JVM 并不会对 stream 进行太多编译优化,对于十分简单的操作,依然建议使用传统 for 循环。

public abstract void setData(String ruleName, Object... ruleData);

public Map<String, Object> metadata() {
return Map.of("id", ruleId, "rule", ruleName, "type", ruleType);
Copy link
Collaborator

Choose a reason for hiding this comment

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

metadata 应当包含规则内容,以允许用户在 WebUI 等其它位置识别具体触发了哪条规则。

}
ctx.status(HttpStatus.BAD_REQUEST);
ctx.json(new SlimMsg(false, Lang.IP_BAN_RULE_URL_WRONG.replace("{}", ruleName)));
ctx.json(new SlimMsg(false, Lang.SUB_RULE_URL_WRONG.replace("{}", ruleName)));
Copy link
Collaborator

Choose a reason for hiding this comment

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

非日志场景推荐使用 String.format(),并将 {} 更换为 %s

@@ -386,6 +390,43 @@ public void banWave() {
// 更新 LIVE_PEERS 用于数据展示
banWaveWatchDog.setLastOperation("Update live peers");
executor.submit(() -> updateLivePeers(peers));
// ===============基于 状态机 的封禁逻辑
Copy link
Collaborator

Choose a reason for hiding this comment

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

考虑拆分成多个函数以降低复杂度

public @NotNull String getConfigName() {
return "ip-address-blocker-rules";
public Logger getLogger() {
return log;
Copy link
Collaborator

Choose a reason for hiding this comment

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

没啥必要,直接上 @slf4j

String msg = Lang.IP_BAN_RULE_DELETED.replace("{}", ruleSubInfo.ruleName());
ruleSubBlocker.deleteRuleSubInfo(ruleId);
ruleSubBlocker.getRules().removeIf(ele -> ele.metadata().get("id").equals(ruleId));
String msg = Lang.SUB_RULE_DELETED.replace("{}", ruleSubInfo.ruleName());
Copy link
Collaborator

Choose a reason for hiding this comment

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

同样,建议使用 %s 和 String.format

if (isAdd && ruleSubInfo != null) {
// 新增时检查规则是否存在
ctx.status(HttpStatus.BAD_REQUEST);
ctx.json(new SlimMsg(false, Lang.IP_BAN_RULE_ID_CONFLICT.replace("{}", ruleId)));
ctx.json(new SlimMsg(false, Lang.SUB_RULE_ID_CONFLICT.replace("{}", ruleId)));
Copy link
Collaborator

Choose a reason for hiding this comment

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

同样,建议使用 %s 和 String.format

return;
}
if (!isAdd && ruleSubInfo == null) {
// 更新时检查规则是否存在
ctx.status(HttpStatus.BAD_REQUEST);
ctx.json(new SlimMsg(false, Lang.IP_BAN_RULE_CANT_FIND.replace("{}", ruleId)));
ctx.json(new SlimMsg(false, Lang.SUB_RULE_CANT_FIND.replace("{}", ruleId)));
Copy link
Collaborator

Choose a reason for hiding this comment

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

同样,建议使用 %s 和 String.format

if (null == configurationSection) {
return new SlimMsg(false, Lang.IP_BAN_RULE_CANT_FIND.replace("{}", ruleId));
return new SlimMsg(false, Lang.SUB_RULE_CANT_FIND.replace("{}", ruleId));
Copy link
Collaborator

Choose a reason for hiding this comment

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

同样,建议使用 %s 和 String.format,太多了 就不一一添加 comment 了

@Gaojianli
Copy link
Member

@PluieM 简单看了下代码,前缀树的构造在哪个部分呀,没找到呀

@PluieM
Copy link
Contributor Author

PluieM commented Jun 20, 2024

还没调整完毕,容我稍后画图解释

@Ghost-chu
Copy link
Collaborator

@coderabbitai 详细解释此PR,如果可以的话,请再画一个图

Copy link
Contributor

coderabbitai bot commented Jun 20, 2024

Tip

For best results, initiate chat on the files or code changes.

@Ghost-chu, here's a detailed explanation of the changes introduced in PR #160, along with a diagram to visually represent the new architecture.

Detailed Explanation

This PR introduces a significant update to the PeerBanHelper project, focusing on enhancing the rule-based peer banning system through a state machine model and expanding the rule types supported by the system.

  1. State Machine-Based Rule Module:

    • A new state machine model (AbstractRuleBlocker) has been introduced. This model serves as the foundation for handling different states of peer connections and deciding the actions based on various match events.
    • The state machine transitions between states like INIT, MATCH, BAN, ACTIVE, and END based on events such as MATCH, HIT, PASS, DISCONNECT, and TIMEOUT.
  2. Refactoring of Modules:

    • The subscription rule module and the PeerID blacklist module have been refactored to utilize the new state machine model. This allows for more dynamic and efficient handling of peer states and rule matching.
  3. Expansion of Rule Types:

    • The system now supports additional rule types such as IP, PEER_ID_CONTAINS, PEER_ID_STARTS_WITH, CLIENT_NAME_CONTAINS, and CLIENT_NAME_STARTS_WITH. This enhancement broadens the scope of the rules that can be applied, making the system more versatile.
  4. Integration with Existing Components:

    • Changes have been made across various components like PeerBanHelperServer, ProfileUpdateScript, and DatabaseHelper to integrate the new rule module and support the expanded rule types.

Architectural Diagram

Below is a diagram illustrating the integration of the state machine model with the rule modules:

Loading
flowchart TD
    A[PeerBanHelperServer] -->|Manages| B[AbstractRuleBlocker]
    B -->|Utilizes| C[StateMachine]
    C --> D[PeerState]
    D --> E[MatchEvents]
    B -->|Controls| F[RuleBlocker]
    F -->|Implements| G[PeerIdBlocker]
    F -->|Implements| H[RuleSubBlocker]
    C -->|Triggers| I[MatchResultDetail]
    I --> J[PeerMatchRecord]

This diagram shows how PeerBanHelperServer manages instances of AbstractRuleBlocker, which utilize a StateMachine to handle different PeerStates based on MatchEvents. The RuleBlocker interface is implemented by specific blockers like PeerIdBlocker and RuleSubBlocker, which are responsible for the actual rule enforcement based on the state transitions.

I hope this provides a clear understanding of the changes and the architecture introduced in this PR. If you have any more questions or need further clarification, feel free to ask!

@Ghost-chu
Copy link
Collaborator

@coderabbitai 详细解释此PR,如果可以的话,请再画一个图

@Ghost-chu
Copy link
Collaborator

@coderabbitai 请详细描述一下 Peer 在此 PR 是如何匹配的。简述各种情况下状态机发生的变化。

Copy link
Contributor

coderabbitai bot commented Jun 20, 2024

Tip

For best results, initiate chat on the files or code changes.

@Ghost-chu, as requested, here's a more detailed explanation of the changes introduced in PR #160, along with a diagram to visually represent the new architecture.

Detailed Explanation

This PR introduces a significant update to the PeerBanHelper project, focusing on enhancing the rule-based peer banning system through a state machine model and expanding the rule types supported by the system.

  1. State Machine-Based Rule Module:

    • A new state machine model (AbstractRuleBlocker) has been introduced. This model serves as the foundation for handling different states of peer connections and deciding the actions based on various match events.
    • The state machine transitions between states like INIT, MATCH, BAN, ACTIVE, and END based on events such as MATCH, HIT, PASS, DISCONNECT, and TIMEOUT.
  2. Refactoring of Modules:

    • The subscription rule module and the PeerID blacklist module have been refactored to utilize the new state machine model. This allows for more dynamic and efficient handling of peer states and rule matching.
  3. Expansion of Rule Types:

    • The system now supports additional rule types such as IP, PEER_ID_CONTAINS, PEER_ID_STARTS_WITH, CLIENT_NAME_CONTAINS, and CLIENT_NAME_STARTS_WITH. This enhancement broadens the scope of the rules that can be applied, making the system more versatile.
  4. Integration with Existing Components:

    • Changes have been made across various components like PeerBanHelperServer, ProfileUpdateScript, and DatabaseHelper to integrate the new rule module and support the expanded rule types.

Architectural Diagram

Below is a diagram illustrating the integration of the state machine model with the rule modules:

Loading
flowchart TD
    A[PeerBanHelperServer] -->|Manages| B[AbstractRuleBlocker]
    B -->|Utilizes| C[StateMachine]
    C --> D[PeerState]
    D --> E[MatchEvents]
    B -->|Controls| F[RuleBlocker]
    F -->|Implements| G[PeerIdBlocker]
    F -->|Implements| H[RuleSubBlocker]
    C -->|Triggers| I[MatchResultDetail]
    I --> J[PeerMatchRecord]

This diagram shows how PeerBanHelperServer manages instances of AbstractRuleBlocker, which utilize a StateMachine to handle different PeerStates based on MatchEvents. The RuleBlocker interface is implemented by specific blockers like PeerIdBlocker and RuleSubBlocker, which are responsible for the actual rule enforcement based on the state transitions.

I hope this provides a clear understanding of the changes and the architecture introduced in this PR. If you have any more questions or need further clarification, feel free to ask!

Copy link
Contributor

coderabbitai bot commented Jun 20, 2024

Tip

For best results, initiate chat on the files or code changes.

@Ghost-chu, 在此 PR 中,Peer 的匹配和状态机的变化是通过新引入的基于状态机模型的规则模块来管理的。这里是详细的解释:

Peer 匹配过程

  1. 初始化 (INIT): 当 Peer 连接时,它首先进入 INIT 状态。
  2. 规则匹配: 根据配置的规则(如 IP、PEER_ID_CONTAINS、PEER_ID_STARTS_WITH、CLIENT_NAME_CONTAINS 和 CLIENT_NAME_STARTS_WITH),系统会检查每个 Peer 是否符合任何规则。
  3. 状态转换:
    • 如果 Peer 匹配某个规则,状态机将触发 MATCH 事件,并可能根据规则的具体要求转移到 BAN 状态。
    • 如果 Peer 不匹配任何规则,状态机可能触发 PASS 事件,保持在 ACTIVE 状态或转移到其他状态,这取决于系统的配置和规则。

状态机的变化

  • MATCH: 当检测到匹配时触发,Peer 可能进入更进一步的检查或直接进入 BAN 状态。
  • HIT: 特定规则匹配成功后,如果规则定义了行动(如断开连接),则触发 HIT 事件,并执行相应操作。
  • PASS: 如果 Peer 未触发任何规则,或者规则检查后决定不采取行动,将触发 PASS 事件。
  • DISCONNECT: 如果 Peer 在任何时候断开连接,将触发 DISCONNECT 事件,并可能清理与该 Peer 相关的任何状态信息。
  • TIMEOUT: 对于需要定时检查的规则,如果达到特定时间而没有新的活动,可能会触发 TIMEOUT 事件。

这个状态机模型允许系统灵活地处理各种 Peer 状态和事件,确保根据实时数据动态调整 Peer 的处理。如果您需要更多信息或有其他问题,请随时提问!

@Ghost-chu
Copy link
Collaborator

@coderabbitai summary

Copy link
Contributor

coderabbitai bot commented Jun 20, 2024

Actions performed

Summary regeneration triggered.

Copy link
Contributor

@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 and nitpick comments (1)
src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java (1)

Line range hint 728-760: Review the peer banning logic for potential optimizations.

The method banPeer is crucial for the functionality of banning peers based on various criteria. Consider optimizing the query operations and the conditions under which peers are banned to enhance performance and reduce computational overhead.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between f05b6bd and ca1a76a.

Files selected for processing (2)
  • src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java (10 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/text/Lang.java (3 hunks)
Additional comments not posted (7)
src/main/java/com/ghostchu/peerbanhelper/text/Lang.java (3)

24-24: Ensure new constants align with the application's functionality.

The new constants for subscription rules (MODULE_IBL_MATCH_SUB_RULE) align with the renaming and functional changes in the rest of the application. This should help maintain consistency across the user interface.


172-202: Review the consistency and correctness of the new subscription rule constants.

The newly added constants for subscription rule updates and their statuses are comprehensive and cover various scenarios (e.g., success, failure, no update). This should enhance the user experience by providing more detailed feedback about the state of rule updates.


215-216: Confirm the new constants are used correctly across the application.

The constants RULE_MODULE_MATCH_TIME and RULE_MODULE_PEER_BAN are well-defined and seem to be part of the new functionality for rule modules. Ensure these constants are used consistently in logging and user messaging within the rule modules.

src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java (4)

Line range hint 75-117: Ensure proper initialization of disconnectTimeout in the constructor.

This change correctly initializes disconnectTimeout with a value from the profile, which is essential for managing peer disconnections based on configured timeouts.


101-110: Refactor moduleManager to be final and ensure thread safety.

Making moduleManager final is a good practice as it enhances thread-safety and ensures that the reference does not change post-initialization, which is crucial in a multi-threaded environment like this.


518-526: Update match records efficiently and handle potential concurrency issues.

The logic for updating matchRecords is sound, but make sure to handle concurrency properly, especially since matchRecords is a ConcurrentHashMap. Consider using atomic operations or locks where necessary to avoid race conditions.


587-596: Ensure new modules are registered correctly and refactor for clarity.

The registration of new modules, such as PeerIdBlocker and RuleSubBlocker, appears correct. However, consider documenting the purpose and functionality of each module during registration to aid future maintainability.

Comment on lines 477 to 478
} catch (InterruptedException e) {
throw new RuntimeException(e);
Copy link
Contributor

Choose a reason for hiding this comment

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

Handle InterruptedException properly by restoring the interrupt status.

- throw new RuntimeException(e);
+ Thread.currentThread().interrupt(); // Restore the interrupted status
// or handle the interruption more appropriately depending on the context

Interrupt handling is crucial in a multi-threaded environment to ensure that the thread's interrupt status is respected and that the system can respond appropriately to interrupts.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Restore the interrupted status

PluieM added 3 commits June 20, 2024 16:41
2、精简RuleBlocker的调用逻辑
…r-new

# Conflicts:
#	src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java
#	src/main/java/com/ghostchu/peerbanhelper/text/Lang.java
@Ghost-chu Ghost-chu added enhancement 功能增强 on-hold Issue/PR 暂时挂起,不要关闭/合并 labels Jun 20, 2024
Copy link
Contributor

@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 and nitpick comments (2)
src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/RuleSubBlocker.java (1)

Line range hint 48-259: RuleSubBlocker effectively manages rule-based blocking with a robust implementation. Consider enhancing error handling in the init method to replace assert statements with more user-friendly error messages.

- assert rule != null;
+ if (rule == null) {
+     log.error("Rule configuration section is missing for rule ID: {}", ruleId);
+     continue;
+ }
src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java (1)

74-74: Consider adding a comment explaining the purpose of disconnectTimeout.

This could improve code readability and maintainability, especially for new developers or during future reviews.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between ca1a76a and 747e552.

Files selected for processing (15)
  • src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java (10 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/AbstractRuleBlocker.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/MatchEvents.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/MatchResultDetail.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/PeerMatchContext.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/PeerState.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/RuleBlocker.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/RuleSubBlocker.java (7 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/RuleSubController.java (14 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/text/Lang.java (3 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/RuleMatcher.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/matcher/IPMatcher.java (2 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/matcher/PrefixMatcher.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/matcher/SubStrMatcher.java (1 hunks)
  • src/main/java/com/ghostchu/peerbanhelper/util/time/ExceptedTime.java (1 hunks)
Files skipped from review as they are similar to previous changes (9)
  • src/main/java/com/ghostchu/peerbanhelper/module/AbstractRuleBlocker.java
  • src/main/java/com/ghostchu/peerbanhelper/module/MatchEvents.java
  • src/main/java/com/ghostchu/peerbanhelper/module/MatchResultDetail.java
  • src/main/java/com/ghostchu/peerbanhelper/module/PeerState.java
  • src/main/java/com/ghostchu/peerbanhelper/module/RuleBlocker.java
  • src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/RuleSubController.java
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/RuleMatcher.java
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/matcher/PrefixMatcher.java
  • src/main/java/com/ghostchu/peerbanhelper/util/rule/matcher/SubStrMatcher.java
Additional comments not posted (28)
src/main/java/com/ghostchu/peerbanhelper/module/PeerMatchContext.java (1)

1-18: Class PeerMatchContext is well-structured to handle various peer match actions using functional programming paradigms. Good use of @Data, @AllArgsConstructor, and @NoArgsConstructor annotations for boilerplate code reduction.

src/main/java/com/ghostchu/peerbanhelper/util/time/ExceptedTime.java (1)

12-12: The addition of STAGE_BAN_WAVE in ExceptedTime centralizes timeout management for related operations, enhancing maintainability and clarity.

src/main/java/com/ghostchu/peerbanhelper/util/rule/matcher/IPMatcher.java (1)

Line range hint 24-85: IPMatcher is effectively designed to handle both exact IP and subnet matches with an optimized approach using a bloom filter. Good encapsulation of matching logic.

src/main/java/com/ghostchu/peerbanhelper/text/Lang.java (19)

24-24: Updated constant name to reflect change from IP blacklist to subscription rules.


172-172: The constant SUB_RULE_UPDATE_FINISH clearly indicates the completion of rule subscription updates.


173-173: The constant SUB_RULE_NO_UPDATE effectively communicates that no updates occurred for the specified subscription rule.


174-174: The constant SUB_RULE_UPDATE_SUCCESS accurately reflects a successful update to a subscription rule.


175-175: The constant SUB_RULE_UPDATE_FAILED clearly indicates a failure in updating the subscription rule.


176-176: The constant SUB_RULE_LOAD_SUCCESS effectively communicates the successful loading of a subscription rule.


177-177: The constant SUB_RULE_UPDATE_LOG_ERROR clearly indicates an error occurred during the logging of a subscription rule update.


178-178: The constant SUB_RULE_USE_CACHE effectively communicates that the local cache was used to successfully load a subscription rule due to a failure in the subscription process.


179-179: The constant SUB_RULE_LOAD_FAILED clearly indicates a failure in loading a subscription rule.


182-182: The constant SUB_RULE_LOAD_CONTENT clearly indicates the content that was loaded for a subscription rule.


184-184: The constant SUB_RULE_NO_ID effectively communicates an error due to an empty subscription rule ID.


185-185: The constant SUB_RULE_ID_CONFLICT clearly indicates a conflict in subscription rule IDs.


186-186: The constant SUB_RULE_CANT_FIND effectively communicates that a specific subscription rule could not be found.


187-187: The constant SUB_RULE_PARAM_WRONG clearly indicates an error due to incorrect parameters for a subscription rule.


188-188: The constant SUB_RULE_URL_WRONG clearly indicates an error due to an incorrect URL for a subscription rule.


189-194: These constants clearly communicate various states and actions related to subscription rules, such as enabling, disabling, updating, saving, and deleting.


195-198: These constants effectively communicate various outcomes of querying subscription rule information and logs.


199-202: These constants clearly communicate various states and actions related to checking and updating the interval for subscription rules.


215-218: These constants clearly communicate various events and states within the rule module, such as match time, peer hit, disconnect, and ban timeout.

src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java (6)

108-108: Initialization of matchRecords appears correct, but ensure thread safety when accessing this map.

Consider adding detailed unit tests to verify thread safety and correctness of operations on matchRecords.


496-496: Ensure that the match records update logic is correct and efficient.

Consider adding more comments to explain the logic, especially how match records are managed and updated.

Also applies to: 498-498, 500-500, 502-502, 504-504


566-566: The registration of modules in registerModules method is updated correctly.

Ensure that all newly registered modules are properly integrated and tested with the existing system.

Also applies to: 567-567, 575-575


707-707: The banPeer method handles the new ban logic using the state machine model effectively.

Ensure that all edge cases are covered in unit tests, especially with different combinations of downloader, torrent, and peer.

Also applies to: 709-709, 710-710, 712-712, 713-713, 715-715, 717-717, 719-719, 720-720, 722-722, 724-724, 744-744, 745-745


100-100: Ensure moduleManager is properly initialized before use in constructors or methods.

Verification successful

The moduleManager is properly initialized within the constructor of the PeerBanHelperServer class before it is used. This ensures that it is correctly set up before any method calls that rely on it.

  • Initialization occurs at: this.moduleManager = new ModuleManager(); within the constructor.
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Search for all occurrences of `moduleManager` to ensure it's initialized before use.
rg --type java 'moduleManager'

Length of output: 3204




Script:

#!/bin/bash
# Search for the PeerBanHelperServer class definition and include a broader range to capture the constructor and initialization blocks.
rg --type java 'class PeerBanHelperServer' -A 50

Length of output: 5483



Script:

#!/bin/bash
# Search for the PeerBanHelperServer class definition and extend the range to capture the full constructor.
rg --type java 'class PeerBanHelperServer' -A 100

Length of output: 10969


114-114: Initialization of disconnectTimeout using profile settings seems correct. Verify that the corresponding configuration exists and is documented.

Verification successful

The disconnect-timeout configuration is indeed present in the codebase, specifically in the ProfileUpdateScript.java file where it is being set.

  • src/main/java/com/ghostchu/peerbanhelper/config/ProfileUpdateScript.java: conf.set("disconnect-timeout", 60000);
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify the existence of 'disconnect-timeout' in configuration files.
rg --type yaml 'disconnect-timeout'

Length of output: 35



Script:

#!/bin/bash
# Description: Verify the existence of 'disconnect-timeout' in JSON and properties configuration files.
rg --type json 'disconnect-timeout'
rg --type properties 'disconnect-timeout'

Length of output: 261



Script:

#!/bin/bash
# Description: Verify the existence of 'disconnect-timeout' in JSON, properties, and conf configuration files.
rg 'disconnect-timeout' --glob '*.json'
rg 'disconnect-timeout' --glob '*.properties'
rg 'disconnect-timeout' --glob '*.conf'

Length of output: 572



Script:

#!/bin/bash
# Description: Verify the existence of 'disconnect-timeout' in all files within the repository.
rg 'disconnect-timeout'

Length of output: 281

@@ -377,7 +378,7 @@ public void banWave() {
banWaveWatchDog.setLastOperation("Reset last status");
// 声明基本集合
// 需要重启的种子列表
Map<Downloader, Collection<Torrent>> needRelaunched = new ConcurrentHashMap<>();
Map<Downloader, List<Torrent>> needRelaunched = new ConcurrentHashMap<>();
Copy link
Contributor

Choose a reason for hiding this comment

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

Refactor the banWave method to improve readability and reduce complexity.

The method is very long and handles multiple responsibilities. Consider breaking it down into smaller, more manageable methods, each handling a specific part of the process.

Also applies to: 393-393, 395-395, 397-397, 399-399, 401-401, 403-403, 405-405, 407-407, 409-409, 427-427, 429-429, 431-431, 433-433, 435-435, 437-437

@Gaojianli
Copy link
Member

感觉没对齐,能看下qq群吗? @PluieM 我说的是类似NFA的文法状态机
9c571254a47f3b770452a728b7707404

@Ghost-chu Ghost-chu marked this pull request as draft June 20, 2024 09:41
@PluieM PluieM closed this Jun 20, 2024
@PluieM PluieM deleted the ruleblocker-new branch June 20, 2024 12:11
PluieM added a commit to PluieM/PeerBanHelper that referenced this pull request Jun 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement 功能增强 on-hold Issue/PR 暂时挂起,不要关闭/合并
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants