Skip to content

Commit

Permalink
Moving to unified ids to support multiple platforms integration
Browse files Browse the repository at this point in the history
  • Loading branch information
Hatry1337 committed Apr 25, 2023
1 parent 8f8838b commit 9fc2f18
Show file tree
Hide file tree
Showing 17 changed files with 286 additions and 171 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "synergy3",
"version": "3.12.2",
"version": "3.13.2",
"description": "Synergy 3 - Powerful Discord BOT Framework.",
"license": "MIT",
"author": {
Expand Down
6 changes: 3 additions & 3 deletions src/EventManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ class EventManager extends EventEmitter{
logger.info(`Fetching system user..`);
await this.bot.users.updateAssociations();

let sys = await this.bot.users.fetchOne(this.bot.client.user?.id ?? "alice");
let sys = await this.bot.users.fetchOne("0");
if(!sys){
logger.info(`No system user. Creating new one..`);
sys = await this.bot.users.createFromDiscord(this.bot.client.user!, [ Access.ADMIN() ]);
logger.info(`Created system user. ID: ${sys.id}`);
sys = await this.bot.users.createFromDiscord(this.bot.client.user!, [ Access.ADMIN() ], true);
logger.info(`Created system user. ID: ${sys.unifiedId}`);
}
logger.info(`Database Synchronized.`);

Expand Down
18 changes: 17 additions & 1 deletion src/InteractionsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@ export default class InteractionsManager{
return cmd;
}

/**
* This method allows to emulate incoming interaction.
* @param interaction interaction to emulate
*/
public emulate(interaction: Discord.Interaction) {
this.onInteractionCreate(interaction).catch(e => GlobalLogger.root.error("Error emulating interaction:", e));
}

/**
* This method allows to asynchronously emulate incoming interaction.
* @param interaction interaction to emulate
*/
public async emulateAsync(interaction: Discord.Interaction) {
await this.onInteractionCreate(interaction).catch(e => GlobalLogger.root.error("Error emulating interaction:", e));
}

/**
* @param name command name
* @param access access targets that allowed to use this command
Expand Down Expand Up @@ -328,7 +344,7 @@ export default class InteractionsManager{
GlobalLogger.root.warn("InteractionsManager.InteractionProcessing: Passed invalid user access target \"", a + "\"");
continue;
}
if(user.id.toString() === res[1] || user.discord.id === res[1]){
if(user.unifiedId === res[1] || user.discord?.id === res[1]){
access_flag = true;
break;
}
Expand Down
17 changes: 6 additions & 11 deletions src/Models/StorageUser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Table, Model, Column, DataType, HasOne } from "sequelize-typescript";
import { Column, DataType, HasOne, Model, Table } from "sequelize-typescript";
import { StorageUserDiscordInfo } from "./StorageUserDiscordInfo";
import { StorageUserEconomyInfo } from "./StorageUserEconomyInfo";
import { UnifiedId, UnifiedIdDataType } from "../UnifiedId";

interface StorageUserMeta{
}
Expand All @@ -11,25 +12,19 @@ interface StorageUserMeta{
export class StorageUser extends Model<StorageUser> {
//Main Options
@Column({
type: DataType.INTEGER,
type: DataType.STRING,
allowNull: false,
primaryKey: true,
autoIncrement: true
defaultValue: () => UnifiedId.generate(UnifiedIdDataType.User).toString(16)
})
declare id: number;
declare unifiedId: string;

@Column({
type: DataType.STRING,
allowNull: false,
})
declare nickname: string;

@Column({
type: DataType.STRING,
allowNull: false,
})
declare discordId: string;

@Column({
type: DataType.JSONB,
allowNull: false,
Expand All @@ -45,7 +40,7 @@ export class StorageUser extends Model<StorageUser> {
declare lang: string;

@HasOne(() => StorageUserDiscordInfo)
declare discord: StorageUserDiscordInfo;
declare discord?: StorageUserDiscordInfo;

@HasOne(() => StorageUserEconomyInfo)
declare economy: StorageUserEconomyInfo;
Expand Down
2 changes: 1 addition & 1 deletion src/Models/StorageUserDiscordInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class StorageUserDiscordInfo extends Model<StorageUserDiscordInfo> {
@ForeignKey(() => StorageUser)
@PrimaryKey
@Column
declare id: number;
declare unifiedId: string;

@BelongsTo(() => StorageUser)
declare user: StorageUser;
Expand Down
10 changes: 5 additions & 5 deletions src/Models/StorageUserEconomyInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,29 @@ export class StorageUserEconomyInfo extends Model<StorageUserEconomyInfo> {
@ForeignKey(() => StorageUser)
@PrimaryKey
@Column
id!: number;
declare unifiedId: string;

@BelongsTo(() => StorageUser)
user!: StorageUser
declare user: StorageUser

//Economy Options
@Column({
type: DataType.REAL,
allowNull: false,
})
economyPoints!: number;
declare economyPoints: number;

@Column({
type: DataType.INTEGER,
allowNull: false,
defaultValue: 1
})
economyLVL!: number;
declare economyLVL: number;

@Column({
type: DataType.INTEGER,
allowNull: false,
defaultValue: 0
})
economyXP!: number;
declare economyXP: number;
}
3 changes: 2 additions & 1 deletion src/ModuleManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ const Modules: Module[] = [];
const ModuleRegistry: Map<string, typeof Module> = new Map();

export default class ModuleManager{
public data: ModuleDataManager = new ModuleDataManager(this.bot);
public data: ModuleDataManager;

constructor(public bot: Synergy){
this.data = new ModuleDataManager(this.bot);
}

public RegisterModule(mod: typeof Module, uuid: string, preLoad: boolean = false){
Expand Down
2 changes: 1 addition & 1 deletion src/Modules/Core/Profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default class Profile extends Module{
title: `${user.nickname}'s profile`,
thumbnail: user.discord?.avatar ? { url: user.discord.avatar } : undefined,
fields: [
{ name: "Info", value: `ID: ${user.id}\n` +
{ name: "Info", value: `ID: ${user.unifiedId}\n` +
`Groups: ${user.groups.join(", ")}\n` +
`Language: ${user.lang}` },

Expand Down
14 changes: 13 additions & 1 deletion src/Structures/Access.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,15 @@ export default class Access {
GlobalLogger.root.warn("Access.Check: Passed invalid user access target \"", a + "\"");
continue;
}
if(user.id.toString() === res[1] || user.discord.id === res[1]){
if(user.unifiedId.toString() === res[1] || user.discord?.id === res[1]){
access_flag = true;
break;
}
}
if(guild && a.startsWith("role")){
if(!user.discord) {
continue;
}
let res = /role<(.*)>/.exec(a);
if(!res || !res[1]){
GlobalLogger.root.warn("Access.Check: Passed invalid role access target \"", a + "\"");
Expand All @@ -80,6 +83,9 @@ export default class Access {
}
}
if(guild && a.startsWith("perm")){
if(!user.discord) {
continue;
}
let res = /perm<(.*)>/.exec(a);
if(!res || !res[1]){
GlobalLogger.root.warn("Access.Check: Passed invalid perm access target \"", a + "\"");
Expand All @@ -95,6 +101,9 @@ export default class Access {
}
}
if(guild && a.startsWith("server_mod")){
if(!user.discord) {
continue;
}
let member = guild.members.cache.get(user.discord.id);
if(member){
let configEntry = user.bot.config.getConfigEntry("guild", "moderator_role");
Expand All @@ -117,6 +126,9 @@ export default class Access {
}
}
if(guild && a.startsWith("server_admin")){
if(!user.discord) {
continue;
}
let member = guild.members.cache.get(user.discord.id);
if(member){
if(member.permissions.has("Administrator")){
Expand Down
2 changes: 1 addition & 1 deletion src/Structures/Errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class MissingPermissionsError extends SynergyUserError {

export class UserAlreadyExistError extends Error {
constructor(user: User | Discord.User){
super(`Error: User ${user instanceof Discord.User ? user.tag : user.nickname}(${user.id}) already exist.`);
super(`Error: User ${user instanceof Discord.User ? `${user.tag}(${user.id})` : `${user.nickname}(${user.unifiedId})`} already exist.`);
}
}

Expand Down
57 changes: 34 additions & 23 deletions src/Structures/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,27 @@ export interface UserDiscordOptions {
}

export interface UserOptions{
id: number;
unifiedId: string;
nickname: string;
groups: string[];
lang: string;
discordId: string;
discord: UserDiscordOptions;
discord?: UserDiscordOptions;
economy: UserEconomyOptions;
}

export default class User implements UserOptions{
public id: number;
public unifiedId: string;
public nickname: string;
public groups: string[];
public lang: string;
public discordId: string;
public economy: UserEconomyOptions;
public discord: UserDiscordOptions;
public discord?: UserDiscordOptions;

constructor(public bot: Synergy, opts: UserOptions){
this.id = opts.id;
this.unifiedId = opts.unifiedId;
this.nickname = opts.nickname;
this.groups = opts.groups;
this.lang = opts.lang;
this.discordId = opts.discordId;
this.economy = opts.economy;
this.discord = opts.discord;
}
Expand All @@ -51,37 +48,51 @@ export default class User implements UserOptions{
return await Access.Check(this, access, guild);
}

public bindDiscord(user: Discord.User) {
this.discord = {
user,
id: user.id,
tag: user.tag,
avatar: user.avatarURL() ?? undefined,
banner: user.bannerURL() ?? undefined,
createdAt: user.createdAt
}
}

public async fetchDiscordUser() {
this.discord.user = await this.bot.client.users.fetch(this.discordId);
if(!this.discord) return;

this.discord.user = await this.bot.client.users.fetch(this.discord.id);
this.discord.tag = this.discord.user.tag;
this.discord.avatar = this.discord.user.displayAvatarURL();
this.discord.banner = this.discord.user.banner ?? undefined;
this.discord.avatar = this.discord.user.avatarURL() ?? undefined;
this.discord.banner = this.discord.user.bannerURL() ?? undefined;
return this.discord.user;
}

public static fromStorageUser(bot: Synergy, storageUser: StorageUser): User {
let discordOpts: UserDiscordOptions = {
id: storageUser.discord.discordId,
tag: storageUser.discord.discordTag,
createdAt: storageUser.discord.discordCreatedAt,
avatar: storageUser.discord.discordAvatar ?? undefined,
banner: storageUser.discord.discordBanner ?? undefined,
user: undefined
};
let discordOpts: UserDiscordOptions | undefined;

if(storageUser.discord) {
discordOpts = {
id: storageUser.discord.discordId,
tag: storageUser.discord.discordTag,
avatar: storageUser.discord.discordAvatar ?? undefined,
banner: storageUser.discord.discordBanner ?? undefined,
createdAt: storageUser.discord.discordCreatedAt,
};
}

let user = new User(bot, {
id: storageUser.id,
return new User(bot, {
unifiedId: storageUser.unifiedId,
nickname: storageUser.nickname,
groups: storageUser.groups,
lang: storageUser.lang,
discordId: storageUser.discordId,
discord: discordOpts,
economy: {
points: storageUser.economy.economyPoints,
lvl: storageUser.economy.economyLVL,
xp: storageUser.economy.economyXP
}
});
return user;
}
}
68 changes: 68 additions & 0 deletions src/UnifiedId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
+--------------------------------------------------------------------+
| Unified ID Binary Structure |
+--------------------------------------------------------------------+
| 64 20 15 0 |
| 11111111111111111111111111111111111111111111 11111 111111111111111 |
+--------------------------------------------------------------------+
+------------------------------------------------------------------------------------------+
| Unified ID components description |
+---------+--------------------------------------------------------------------------------+
| [64-20] | Milliseconds from RainbowBOT Epoch (April 28 of 2019 TZ=GMT+0 - 1556409600000) |
+---------+--------------------------------------------------------------------------------+
| [20-15] | Associated data type: |
| | 0 - Reserved |
| | 1 - Any data |
| | 2 - User |
| | 3 - Discord Guild |
| | 4 - Discord Channel |
| | 5 - Other channel |
| | ... |
+---------+--------------------------------------------------------------------------------+
| [15-00] | Increment number |
+---------+--------------------------------------------------------------------------------+
*/

export const RainbowBOTEpoch = 1556409600000;

export enum UnifiedIdDataType {
RESERVED = 0,
AnyData = 1,
User = 2,
DiscordGuild = 3,
DiscordChannel = 4,
OtherChannel = 5,
}

export class UnifiedId {
private static increment = 0;
public static generate(dataType: UnifiedIdDataType = UnifiedIdDataType.AnyData, milliseconds?: number, increment?: number) {
if(milliseconds === undefined) {
milliseconds = new Date().getTime() - RainbowBOTEpoch;
}
if(increment === undefined) {
UnifiedId.increment++;
if(UnifiedId.increment >= 32768) {
UnifiedId.increment = 0;
}
increment = UnifiedId.increment;
}

return BigInt(increment) +
(BigInt(dataType) << 15n) +
(BigInt(milliseconds) << 20n)
}

public static parse(id: bigint) {
let milliseconds = id >> 20n;
let dataType = (id - (milliseconds << 20n)) >> 15n;
let increment = (id - (milliseconds << 20n) - (dataType << 15n));

return {
milliseconds: Number(milliseconds),
dataType: Number(dataType) as UnifiedIdDataType,
increment: Number(increment)
}
}
}
Loading

0 comments on commit 9fc2f18

Please sign in to comment.