getKey method

int getKey(
  1. CommandContext context
)

Returns an ID that uniquely represents the bucket context was sorted on, based on type.

For simple types, this process is simple enough. For example, if type is CooldownType.channel, then this method returns an ID that uniquely represents the context's ID (more precisely, Object.hashAll([context.channel.id.id])), and all contexts executed in that channel will be given the same ID.

For combined types, the process is different. For example, if type is CooldownType.guild | CooldownType.user, then this method returns an ID that uniquely represents the combination of the context's user and guild (more precisely, Object.hashAll([context.guild.id.id, context.user.id.id])). This means that:

  • Same user, same guild: same key;
  • Different user, different guild: different key;
  • Same guild, different user: different key;
  • Different guild, Different user: different key.

You might also be interested in:

  • type, which determines which values from context are combined to create a key.

Implementation

// TODO: Move away from [int] in order to reduce the risk of hash collisions.
int getKey(CommandContext context) {
  List<int> keys = [];

  if (type.has(CooldownType.category)) {
    if (context.guild != null) {
      keys.add((context.channel as GuildChannel).parentId?.value ?? context.channel.id.value);
    } else {
      keys.add(context.channel.id.value);
    }
  }

  if (type.has(CooldownType.channel)) {
    keys.add(context.channel.id.value);
  }

  if (type.has(CooldownType.command)) {
    keys.add(context.command.hashCode);
  }

  if (type.has(CooldownType.global)) {
    keys.add(0);
  }

  if (type.value & CooldownType.guild.value != 0) {
    keys.add(context.guild?.id.value ?? context.user.id.value);
  }

  if (type.has(CooldownType.role)) {
    if (context.member != null) {
      keys.add(
        context.member!.roles
                .fold<Role?>(
                  null,
                  (previousValue, element) {
                    final cached = element.manager.cache[element.id];

                    // TODO: Need to fetch if not cached
                    if (cached == null) {
                      return previousValue;
                    }

                    if (previousValue == null) {
                      return cached;
                    }

                    return previousValue.position > cached.position ? previousValue : cached;
                  },
                )
                ?.id
                .value ??
            context.guild!.id.value,
      );
    } else {
      keys.add(context.user.id.value);
    }
  }

  if (type.has(CooldownType.user)) {
    keys.add(context.user.id.value);
  }

  return Object.hashAll(keys);
}