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

Add StaticFilter trait #515

Merged
merged 4 commits into from
Apr 19, 2022
Merged

Add StaticFilter trait #515

merged 4 commits into from
Apr 19, 2022

Conversation

XAMPPRocky
Copy link
Collaborator

@XAMPPRocky XAMPPRocky commented Apr 13, 2022

This PR is borne out of initially an effort to pull the yaml_to_protobuf changes to FilterFactory from #506 into a separate PR, and also add a protobuf_to_yaml method. However adding another new method was pretty tedious, and when thinking more holistically about the problem of converting configuration back and forth from YAML and Protobuf, I realised that we needed a more generic solution that would allow us to statically only define the types and have the same dynamic behaviour.

This thought process led me to this PR which adds a new StaticFilter trait which does exactly that. Now if you're writing a filter in Rust you no longer have to define a FilterFactory to construct it, you only implement StaticFilter and Filter, and then Quilkin will automatically at compile-time generate a virtual table safe version of StaticFilter (still called FilterFactory for the sake of not changing everything all at once).

This new trait design effectively eliminates all boilerplate needed when defining your own filter. For example; this is entire definition for the Compress as a filter (excluding the actual Filter impl). As shown, nearly everything is defined statically with types and constants, the only behaviour needed to be implemented is converting from an Option<Self::Configuration> into a Self.

impl StaticFilter for Compress {
    const NAME: &'static str = "quilkin.filters.compress.v1alpha1.Compress";
    type Configuration = Config;
    type BinaryConfiguration = proto::Compress;

    fn new(config: Option<Self::Configuration>) -> Result<Self, Error> {
        Ok(Compress::new(
            Self::ensure_config_exists(config)?,
            Metrics::new()?,
        ))
    }
}

It's hard to understate how much this single abstraction saves in terms of time and effort. The seperation provides two key things, the most obvious of which is mostly type-based API that is verified at compile-time for getting access to a filter and its configuration. The second benefit is that having a seperate trait allows us to split the dynamic dispatch FilterFactory functionality, this means that changes to FilterFactory have no affect on StaticFilter definitions. This is how this PR is able to add two safely add new FilterFactory methods which allow you to dynamically transcode the configuration format, and for it to still be net negative in terms of code added.

Breaking Changes

  • Filter modules no longer expose their name through a module level constant, instead preferring StaticFilter::NAME.
  • Filter modules no longer expose a factory free function, use StaticFilter::factory to achieve the same effect.

@github-actions

This comment was marked as outdated.

@github-actions

This comment was marked as outdated.

@github-actions

This comment was marked as outdated.

@github-actions

This comment was marked as outdated.

@github-actions

This comment was marked as outdated.

1 similar comment
@github-actions

This comment was marked as resolved.

Copy link
Contributor

@markmandel markmandel left a comment

Choose a reason for hiding this comment

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

This is a really nice refactor!!!

The "writing a customer filter" documentation needs a once over to update to this new architecture though (you may well have been waiting to do that post initial review).

Static: serde::Serialize
+ for<'de> serde::Deserialize<'de>
+ TryFrom<Dynamic, Error = ConvertProtoConfigError>,
BinaryConfiguration: prost::Message + Default,
Copy link
Contributor

Choose a reason for hiding this comment

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

That is a nice renaming 👍🏻

+ for<'de> serde::Deserialize<'de>
+ TryFrom<Dynamic, Error = ConvertProtoConfigError>,
BinaryConfiguration: prost::Message + Default,
TextConfiguration:
Copy link
Contributor

Choose a reason for hiding this comment

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

StringConfiguration ? (Rather than TextConfiguration)?

Just a possible suggestion, non-blocking.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I chose Text over String because String is a specific type in Rust as opposed to just "human readable", and it's shorter.

src/filters.rs Outdated Show resolved Hide resolved
docs/src/filters/writing_custom_filters.md Outdated Show resolved Hide resolved
docs/src/filters/writing_custom_filters.md Outdated Show resolved Hide resolved
docs/src/filters/writing_custom_filters.md Outdated Show resolved Hide resolved
docs/src/filters/writing_custom_filters.md Outdated Show resolved Hide resolved
docs/src/filters/writing_custom_filters.md Outdated Show resolved Hide resolved
@markmandel markmandel added kind/feature New feature or request kind/breaking Changes to functionality, API, etc. labels Apr 18, 2022
Copy link
Contributor

@bombsimon bombsimon left a comment

Choose a reason for hiding this comment

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

Looks like a nice way to implement filters!

docs/src/filters/writing_custom_filters.md Outdated Show resolved Hide resolved
examples/quilkin-filter-example/src/main.rs Show resolved Hide resolved
@github-actions
Copy link

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

1 similar comment
@github-actions
Copy link

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

@github-actions
Copy link

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

@github-actions
Copy link

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

@github-actions
Copy link

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

Copy link
Contributor

@bombsimon bombsimon left a comment

Choose a reason for hiding this comment

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

Really nice documentation update, I think it's great to have the fully working code example in examples and making the implementation details clearer. Also nice with example on how to test the filter with nc!

@github-actions
Copy link

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

@github-actions
Copy link

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

@github-actions
Copy link

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

@github-actions
Copy link

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

@github-actions
Copy link

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

@quilkin-bot
Copy link
Collaborator

Build Succeeded 🥳

Build Id: 65b0ff9a-f7a0-49d3-86e5-5588731e0a74

To build this version:

git fetch [email protected]:googleforgames/quilkin.git pull/515/head:pr_515 && git checkout pr_515
cargo build

@XAMPPRocky XAMPPRocky merged commit d38fb3f into main Apr 19, 2022
@XAMPPRocky XAMPPRocky deleted the ep/static-filter branch April 19, 2022 15:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/breaking Changes to functionality, API, etc. kind/feature New feature or request size/xl
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants