CloudNetService / CloudNet

A modern application that can dynamically and easily deliver Minecraft oriented software
https://cloudnetservice.eu
Apache License 2.0
369 stars 115 forks source link

Template Prototypes #1354

Open HugKitten opened 5 months ago

HugKitten commented 5 months ago

Describe the new feature

Blueprints for templates!

I created this suggestion after finding the configuration options for templates too stiff and lacking of customization. I didn't like that I had to search for a module for each use case, and found many of the unofficial modules undocumented, unmaintained or broken. In the end, I thought it would be better for a single unified setup that can be used across any setup regardless of plugin. This means something that would work for any permission plugin, moderation plugin, database plugin, etc. I think the best way to do this is by allowing a special extension type for templates that allows for data to be used. I have documented some examples below.

Using the task name from config files

LuckPerms/config.yml.prototype

# @name becomes the name of the task
server: @name
sync-minutes: 10
watch-files: false

Using the task and group properties from config files

LiteBans/config.yml.prototype

server_name: '@properties.litebans.serverName'
default_server_scope: '@properties.litebans.defaultServerScope'

Reusing velocity forwarding secret key across all instances

forwarding.secret

@properties.forwardingSecret

Configuring seperate databases for test nodes and deployment nodes:

Test config

"properties": {
    "mysql": {
      "host" : "test-host",
      "port" : "test-port",
      "user" : "test-user",
      "password" : "test-password"
    }
  }

Deployment config

"properties": {
    "mysql": {
      "host" : "depolyment-host",
      "port" : "depolyment-port",
      "user" : "depolyment-user",
      "password" : "depolyment-password"
    }
  }

TheNewEconomy/data.yml.prototype

Data:
  Sync:
    Redis:
      Host: "@properties.mysql.host"
      Port: @properties.mysql.port
      User: "@properties.mysql.user"
      Password: "@properties.mysql.password"

Considerations

How should we escape the @ character in templates?

We could use an escape sequence such as @@ or \@.

Benefits of @@ The escape sequence is isolated to a single character. The user won't have to use \ for \ characters.

Benefits of \@ The escape sequence becomes more readable. The escape of any character is supported. The escape sequence allows for future modifiers such as !, #, or $ in the future. Variable key starting with @@ are still possible.

How do we handle files that need the .prototype extension?

There are two ways we can counter this. We could either ask the user to rename the file into .prototype.prototype, or we can use the @ declaration to signal that a file is a prototype.

Benefits of .prototype.prototype hack Easy to use, and less complicated for end user. The @ symbol stays clearly defined.

Benefits of @ Supports binary files that have the @ character. Supports copying files that have the @ character from a running server. Ensures future versions are backwards compatible. Supports custom metadata that can be used by modules.

How do we get the task-id when the variable is not part of the config file?

There are two ways to do this. We could use the @task-id variable, or we could add a context for where we want to retrieve the data.

Benefits of @task-id Easy to use, and less complicated to setup. Does not require adding contexts like "service", "task", or "node".

Benefits of context Far more modular. Data sources can be defined for data such as task id or group properties. Modules can extend templates by adding their own context. The context default: could be used for cases where context is not defined.

How could we implant context?

LuckPerms/context.json.prototype

{
  "static-contexts": {
    "server": "@service:name",
    "server-group": "@task:name",
    "server-number": "@task:id",
    "node": "@node:name",
    "some-other-data": "@default:properties.some-other-data"
  },
  "default-contexts": {
    "server": "@service:name"
  }
}

Why do you need this feature?

So that I can decrease the amount templates I would need to create when the templates have nearly identical files, and to decouple data from templates. This system unifies automatically file editing in an easily understood way, and does not require the user to download a module for each individual use case they have. This could also be in place of the current port and host binding system to allow for more dynamic support of other types of servers.

Alternatives

Individual modules

We could use a module to match every use case, but often times this is not feasible for the end user, as modules don't always exist for a particular setup

PlaceholderAPI

Some plugins allow for placeholders from CloudNet to be used. This is great for plugins that uses placeholders, but not all do. This also does not help in cases where placeholder data is loaded far too late to be of any use. (Such as data that is required before the server is started)

Modules that uses placeholders

There are unofficial modules that exist that uses special placeholders. I find their implantation too crude, since the files either have to be manually defined or apply to everything. They also tend to be less extendable and usually only supports data from a single source, rather then from multiple contexts (such as groups, or task).

Issue uniqueness