{"id":17347896,"url":"https://github.com/floriansw/cftools-relay","last_synced_at":"2025-04-14T21:02:42.553Z","repository":{"id":54601232,"uuid":"420442516","full_name":"FlorianSW/cftools-relay","owner":"FlorianSW","description":"An easy to use relay for cftools webhook events piped to Discord when filter rules match.","archived":false,"fork":false,"pushed_at":"2023-05-06T14:51:30.000Z","size":3931,"stargazers_count":6,"open_issues_count":2,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-02-06T21:44:44.894Z","etag":null,"topics":["cftools","discord","go"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FlorianSW.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["https://www.paypal.com/donate?hosted_button_id=C2EYFV3G8Y8P6"]}},"created_at":"2021-10-23T14:57:50.000Z","updated_at":"2024-09-04T18:42:13.000Z","dependencies_parsed_at":"2024-06-20T00:04:09.740Z","dependency_job_id":"e6b0e1fc-1aa6-47e6-b09f-b6506ba8ca0b","html_url":"https://github.com/FlorianSW/cftools-relay","commit_stats":{"total_commits":46,"total_committers":2,"mean_commits":23.0,"dds":0.04347826086956519,"last_synced_commit":"05a29e90a82ba0c10470c1fd2a16a7bc66bd4787"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlorianSW%2Fcftools-relay","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlorianSW%2Fcftools-relay/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlorianSW%2Fcftools-relay/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlorianSW%2Fcftools-relay/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FlorianSW","download_url":"https://codeload.github.com/FlorianSW/cftools-relay/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240250355,"owners_count":19771778,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cftools","discord","go"],"created_at":"2024-10-15T16:50:31.109Z","updated_at":"2025-02-26T02:31:24.490Z","avatar_url":"https://github.com/FlorianSW.png","language":"Go","funding_links":["https://www.paypal.com/donate?hosted_button_id=C2EYFV3G8Y8P6"],"categories":[],"sub_categories":[],"readme":"# CFTools Relay\n\n[![Discord](https://img.shields.io/discord/729467994832371813?color=7289da\u0026label=Discord\u0026logo=discord\u0026logoColor=ffffff\u0026style=flat-square)](https://go2tech.de/discord)\n[![Tests](https://img.shields.io/github/workflow/status/FlorianSW/cftools-relay/build?label=tests\u0026style=flat-square)](https://github.com/FlorianSW/cftools-relay/actions/workflows/build.yml)\n\nCFTools Relay is an easy-to-use, still in development, tool that allows you to subscribe to CFTools Cloud Webhook events and forward them to a different target.\nRight now, the only target that is supported is as Discord Webhook URL.\n\n## Why?\n\nCFTools Relay is a tool that is mostly done to allow filtering for specific CFTools events.\nCFTools Cloud already provides a way to send Webhooks for specific events to Discord, however, apart from the event name, there is no additional filter criteria that can be applied.\n\nIf one, e.g., would like to get a notification in Discord only, if a player kills another player from more than 500 meters away, potentially with a specific weapon (like an IJ 70) only, this is currently not possible with CFTools Webhooks.\nCFTools Relay allows to define such filters, which are applied to the incoming Webhook events.\nOnly if at least one filter, with all filter rules, match the event, it will be forwarded/relayed to Discord.\n\n## Should I use this tool?\n\nIf you do not need to filter Webhook events based on data that is within an event (rather than just the event type), then you SHOULD NOT use this tool.\nIt is only increasing complexity in this case, and you can achieve the very same outcome with the CFTools Cloud builtin Webhook-to-Discord feature.\nSimply use that.\n\nIf you, however, need some more filter logic on top of your Webhook events to further reduce the amount of messages your channel is flooded with, this tool might be of help.\n\n## Installation\n\nThe installation is as simple as downloading the latest version of this tool, put it somewhere and start it, either by double-clicking on the exe file (for Windows OS) or running the tool in a terminal (for Linux and Windows OS).\n\n### Download the latest version\n\nYou can either visit the [release page](https://github.com/FlorianSW/cftools-relay/releases) to download the latest released version (which might miss some features from the current development version).\n\nAlternatively, you can visit the [automated build page](https://github.com/FlorianSW/cftools-relay/actions/workflows/build.yml), select the most recent successful run (with a green checkmark) and download the artifact for your operating system from the Artifacts section.\n\n## Configuration\n\nUpon the first start of the tool, it will automatically create a configuration file, named `config.json` in the same directory as the binary.\n\n### Check port of the tool and your firewall\n\nThis tool will start an internal webserver, which is used to handle webhook events sent from CFTools to it.\nThe webserver, by default, uses port 8080 to listen on.\nYou need to ensure that this port is available to the tool and not used by another program/process already (like another webserver).\nIf you do not want to use port 8080 for this tool, you can change the port in the created configuration file.\n\nAlso, make sure that the port you configured (or the default one) is whitelisted in your firewall configuration.\nThe CFTools Relay is using an unencrypted connection using http.\nIf you want to use a TLS-encrypted connection for your webhook messages, you may want to setup a reverse proxy for this tool, which handles the TLS termination.\nA setup like that is out-of-scope of this README.\n\n### First time setup\n\nWhen you setup this tool the first time, you need to do some basic steps in order to create and verify the webhook in the CFTools Cloud console:\n\n1. Start the tool (if you did not do that already) and ensure it is able to receive web requests (see _Check port of the tool and your firewall_)\n2. Open the `config.json` of CFTools Relay in your favourite text editor\n3. Create a new server entry in the `servers` object of the config and choose a name for the server (you can not use whitespaces or other characters that are not URL-safe). It should look like this (when your server name is `aServerName`):\n    - `\"servers\": {\"aServerName\": {\"Secret\": \"\"}},`\n4. Go to the CFTools Cloud Dashboard and open the server where the webhook should be added to\n5. Navigate to the Manage -\u003e Integrations page of that server\n6. Add a new Webhook with the _New Webhook_ button\n7. Enter the Webhook URL:\n   - It consists of the public IP address or domain of your server (e.g. http://123.123.123.123)\n   - appended is the Port (by default 8080) separated by a colon (:8080)\n   - at the end it needs to have a fixed path together with the server name: `/cftools-webhook/aServerName`\n   - For the example values above, the full webhook URL looks like: `http://123.123.123.123:8080/cftools-webhook/aServerName`\n8. Select `CFTools CLoud (Hephaistos v1)` as the _Payload format_\n9. Click _Deploy_\n10. Reload the page and make sure it shows a green shield (which means _Verified and active_) next to the newly created webhook\n11. Open the Webhook details and copy the value in the _Secret_ field\n12. Go back to the `config.json` of CFTools Relay in your text editor\n13. Paste the copied secret into the value of the `secret` field of your previously created server. It should then look like this (when your secret is `abc123`):\n    - `\"servers\": {\"aServerName\": \"abc123\"},`\n14. Save the `config.json` file and restart the CFTools Relay tool\n15. Go back to the Webhook details page of CFTools Cloud and select every event you want the CFTools Relay to receive\n16. Hit _Save_\n\nYou're done with the configuration on the CFTools side.\nGiven CFTools Relay does not know where to relay the webhook event messages to right now, you need to configure the Discord target:\n\n1. Go to the Discord channel of your choice where the Webhook messages should be relayed to\n2. Open the settings of this channel\n3. Navigate to the _Integrations_ section of the settings\n4. Create a new webhook (or use an existing one, up to you)\n5. Copy the _Webhook URL_ value\n6. Open the `config.json` of CFTools Relay in your favourite text editor 7Paste the copied URL into the value of the `discord.webhook_url` field inside the config. It should then look like this (when your URL is `http://example.com`):\n```json\n\"discord\": {\n  \"webhook_url\": \"http://example.com\"\n}\n```\n7. Save the `config.json` file and restart the CFTools Relay tool\n\nThat's it.\nThe first time configuration is now done and CFTools Relay will now start to forward Webhook events from CFTools Cloud to your discord channel.\n\n### Multiple server setup\n\nCFTools-relay supports multiple server out-of-the box.\nYou can either run multiple instances of the tool (when you do not want to share the data of all servers in a shared data basis), or you can use one instance of CFTools-relay to serve webhooks of multiple CFTools servers.\n\nIn order to serve multiple webhook events from multiple servers in a single CFTools-relay instance, you need to configure one server object within the `servers` object of the config and set the secret as explained in the previous chapter.\nAn example of how such a setup looks like:\n```json\n  \"servers\": {\n    \"firstServer\": {\n      \"secret\": \"the-secret\",\n      \"name\": \"A custom ServerName\"\n    },\n    \"secondServer\": {\n      \"secret\": \"the-secret\"\n    }\n  },\n```\n\n### Filter configuration\n\nThe main use case of CFTools Relay is to be able to filter events that should be forwarded to Discord.\nBy default, there are no filters set up, which makes CFTools Relay to relay all messages to Discord.\n\nThere are two main concepts to understand before using filters:\n\n**Filters:**\nYou can have 0-n filters configured in CFTools Relay.\nFilters are evaluated independently of each other.\nCFTools-Relay will go through each filter one-by-one to match the event against.\nEach matching filter will be processed, which means that the filters are combined with an OR operator.\nBecause of that, if you define multiple filters which would match a single event, the event may be relayed multiple times as well.\nThe only required field for filters is the event name this filter should apply to.\n\n**Rules:**\nEach filter can have 0-n rules that are evaluated to the webhook event.\nOnly if all defined rules match the event, the filter evaluates to \"match the event\", which would make the event be relayed to Discord.\nRules are therefore combined with an AND operator.\n\nRules allow you to define more in-depth filtering on Webhook events, as they allow you to compare specific fields to values you define.\nThe available fields heavily depend on the Webhook event type (see the JSON files in the `payloads/` folder of this project for some information).\n\nA usual configuration with one example filter looks like:\n\n```json\n{\n  \"port\": 8080,\n  \"secret\": \"...\",\n  \"discord\": {\n    \"webhook_url\": \"...\"\n  },\n  \"filter\": [\n    {\n      \"event\": \"user.join\",\n      \"rules\": null\n    },\n    {\n      \"event\": \"user.leave\",\n      \"rules\": null\n    }\n  ]\n}\n```\n\nThis filter will make CFTools Relay to only relay events with the type `user.join` and `user.leave`.\n\n#### Example 1: Relay kill event when distance is greater than 1000 meter\n\nIf you wish to get a kill notification in your Discord channel only, if the distance between the _Victim_ and the _Murderer_ is greater than 1000 meters, you can add the following filter:\n\n```json\n{\n  \"event\": \"player.kill\",\n  \"rules\": [\n    {\n      \"comparator\": \"gt\",\n      \"field\": \"distance\",\n      \"value\": 1000\n    }\n  ]\n}\n```\n\n#### Example 2: Relay kill event when distance is greater than 100 meter with an IJ-70\n\nBased on the previous example, you can also combine multiple rules and make filters that, e.g., relay a message to Discord only, if the kill was made over 100 meters between the Victim and the Murderer, as well as if the murderer used an IJ-70:\n\n```json\n{\n  \"event\": \"player.kill\",\n  \"rules\": [\n    {\n      \"comparator\": \"gt\",\n      \"field\": \"distance\",\n      \"value\": 100\n    },\n    {\n      \"comparator\": \"eq\",\n      \"field\": \"weapon\",\n      \"value\": \"IJ-70\"\n    }\n  ]\n}\n```\n\n#### Example 3: Relay kill message when done with one of multiple weapons and over a specific distance\n\nThis example filter configuration will relay a `player.kill` message only, if the murderer used an AKM or an M16-A2 and made the kill over 1000 meter away.\n\n```json\n{\n  \"event\": \"player.kill\",\n  \"rules\": [\n     {\n        \"comparator\": \"gt\",\n        \"field\": \"distance\",\n        \"value\": 100\n     },\n     {\n        \"comparator\": \"oneOf\",\n        \"field\": \"weapon\",\n        \"value\": [\"KA-M\", \"M16-A2\"]\n     }\n  ]\n}\n```\n\n#### Available Comparators\n\nThe following table lists the available Comparators for filter rules:\n\n| Comparator   | Explanation |\n|--------------|-------------|\n| `eq`         | `Equals` comparator, matches only, if the value of the configured `field` in the event is exactly the configured `value`. This comparator is case-sensitive. |\n| `gt`         | `Greater than or equals` comparator, matches only, if the value of the configured `field` in the event is a numeric value and is greater than or equals the configured `value`. This comparator never matches when the value is not a numeric field. |\n| `lt`         | `Less than or equals` comparator, matches only, if the value of the configured `field` in the event is a numeric value and is les than or equals the configured `value`. This comparator never matches when the value is not a numeric field. |\n| `contains`   | `Contains` comparator, matches only, if the value of the configured `field` in the event is a contains the configured `value`. This is a wildcard matcher, which is equivalent to `*value*` is wildcards would exist. |\n| `startsWith` | `Starts with` comparator, same as `contains` with the only difference, that the field value needs to start with the configured value (`value*` instead of `*value*`). |\n| `endsWith`   | `Ends with` comparator, same as `contains` with the only difference, that the field value needs to end with the configured value (`*value` instead of `*value*`). |\n| `oneOf`      | `One of` comparator, matches when the value of the configured `field` in the event is included in the list of values configured in `value`. The `value` needs to be an array of strings. If a string is given only, this comparator behaves like `eq`. |\n\n## Virtual Fields\n\nIn addition to the fields received via the webhook from CFTools, CFTools Relay may inject available data for the specific event in it's own fields.\nThese fields are also called _virtual fields_ as they are only present and usable within CFTools Relay rule configuration.\n\nVirtual Fields aim to provide context information for an event within the stream of incoming webhook events.\nThey allow to have filters match when, e.g., a specific threshold of events is reached, instead of relaying each and every webhook event.\n\nYou can use each of the below listed virtual fields as the `field` name in any rule configuration.\nAs virtual fields may be related to the time-series of events, you need to specify the timeframe for which the virtual field should be evaluated on.\nIf you do not specify this value, a default of 1 hour is assumed.\nThe time-frame is the amount of time and a unit, combined in a single string, e.g. \"1h\" for one hour or \"30m\" for 30 minutes.\nAvailable units can be found in [this documentation](https://pkg.go.dev/time#ParseDuration).\n\nEvents are associated to the CFTools ID they are about and are only recognized for virtual fields of the same player.\nFor events that may have multiple CFTools IDs (like `player.kill`, which has a victim and a murderer CFTools ID), the event is persisted for the CFTools ID, which matches the event the most (`player.kill` is an event of a kill, which is associated with the murderer).\nFor each CFTools ID, a maximum of 100 events are preserved before the most historical events are truncated/removed.\n\n### Available Virtual Fields\n\n| Field name          | Explanation |\n|---------------------|-------------|\n| `vf_event_count`    | A simple counter. Counts every event with the same `type` (e.g. `player.kill` for the specified time-frame. |\n\n#### Example 1: Relay kill message only, when 5 kills of the same player within the last hour\n\nThe following example will only relay the Webhook to Discord, if the murderer had 5 kills in the last hour (including the currently evaluated one):\n\n```json\n{\n  \"event\": \"player.kill\",\n  \"rules\": [\n    {\n      \"comparator\": \"gt\",\n      \"field\": \"vf_event_count\",\n      \"value\": 5,\n      \"since\": \"1h\"\n    }\n  ]\n}\n```\n\n#### Example 2: Relay 5th kill message only\n\nBased on the previous example, the set of rules in this example will _only_ relay the 5th kill message.\nKill events that appear after that are ignored.\n\n```json\n{\n  \"event\": \"player.kill\",\n  \"rules\": [\n    {\n      \"comparator\": \"gt\",\n      \"field\": \"vf_event_count\",\n      \"value\": 5,\n      \"since\": \"1h\"\n    },\n    {\n      \"comparator\": \"lt\",\n      \"field\": \"vf_event_count\",\n      \"value\": 5,\n      \"since\": \"1h\"\n    }\n  ]\n}\n```\n\n## Custom message \u0026 color\n\nWhen relaying a message to your discord, CFTools Relay uses a default message, which depends on the type of event.\nIt also chooses a default color for the embedded message, which is currently dark blue.\n\nOptionally, you can define a custom message as well as a custom color for the message on a filter, which is used whenever the filter matches.\nBoth options are optional and do not depend on each other.\nWhen defining a custom message for a filter, all the metadata of the message will still be relayed to your discord channel.\n\nColor and message is only available when using the `rich` format type, which is the default.\nIf you choose the `text` format type, the message will be relayed with as a simple text message.\nYou may define your own template, which gives you the possibility to define what fields are forwarded in the message and in what format.\nSee the below examples for more information about that.\n\n### Example 1: Configure a custom message for a filter\n\nThe following filter configuration will use `A custom message` when the first filter matches, and the default when the second matches.\n\n```json\n  \"filter\": [\n    {\n      \"event\": \"user.join\",\n      \"rules\": null,\n      \"format\": {\n        \"type\": \"rich\",\n        \"parameters\": {\n          \"message\": \"A custom message\"\n        }\n      }\n    },\n    {\n      \"event\": \"user.leave\",\n      \"rules\": null\n    }\n  ]\n```\n\n### Example 2: Configure a custom color for a filter\n\nThe following filter configuration will use dark green as an embed color when the first filter matches, and the default when the second matches.\n\n```json\n  \"filter\": [\n    {\n      \"event\": \"user.join\",\n      \"rules\": null,\n      \"format\": {\n         \"type\": \"rich\",\n         \"parameters\": {\n           \"color\": \"DARK_GREEN\"\n         }\n      }\n    },\n    {\n      \"event\": \"user.leave\",\n      \"rules\": null\n    }\n  ]\n```\n\n### Example 3: Using the `text` format for `user.chat` events\n\nThe following filter will use the `text` format type to forward `user.chat` events in a more readable way.\nThe template can access all fields of the event the filter should match on (see the `payloads/` directory for some example events and their available fields).\nFor more information about the template syntax, refer to the go `text/template` [package documentation](https://pkg.go.dev/text/template).\n\n```json\n  \"filter\": [\n    {\n      \"event\": \"user.chat\",\n      \"rules\": null,\n      \"format\": {\n         \"type\": \"text\",\n         \"parameters\": {\n           \"template\": \"[**{{.channel}}**] *{{.player_name}}*: {{.message}}\"\n         }\n      }\n    },\n    {\n      \"event\": \"user.leave\",\n      \"rules\": null\n    }\n  ]\n```\n\n## Custom username\n\nWhen relaying messages to Discord, cftools-relay uses a default username (`CFTools-Relay`).\nIf you want to use a different name instead, you can specify one individually in your filter using the `username` parameter.\n\n### Example 1: Using different usernames for different filters\n\n```json\n  \"filter\": [\n    {\n      \"event\": \"user.chat\",\n      \"rules\": null,\n      \"username\": \"SomeOtherUsername\"\n    },\n    {\n      \"event\": \"user.leave\",\n      \"rules\": null\n    }\n  ]\n```\n\n### Supported color names\n\nYou can choose from a pre-configured color palette.\nSupported color names can be found in the [source code](./internal/domain/filter.go).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffloriansw%2Fcftools-relay","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffloriansw%2Fcftools-relay","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffloriansw%2Fcftools-relay/lists"}