refactor progress
This commit is contained in:
233
packages/api/src/voice/VoiceRepository.tsx
Normal file
233
packages/api/src/voice/VoiceRepository.tsx
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {createGuildIDSet, createUserIDSet} from '@fluxer/api/src/BrandedTypes';
|
||||
import {
|
||||
BatchBuilder,
|
||||
defineTable,
|
||||
deleteOneOrMany,
|
||||
fetchMany,
|
||||
fetchOne,
|
||||
upsertOne,
|
||||
} from '@fluxer/api/src/database/Cassandra';
|
||||
import {
|
||||
VOICE_REGION_COLUMNS,
|
||||
VOICE_SERVER_COLUMNS,
|
||||
type VoiceRegionRow,
|
||||
type VoiceServerRow,
|
||||
} from '@fluxer/api/src/database/types/VoiceTypes';
|
||||
import type {IVoiceRepository} from '@fluxer/api/src/voice/IVoiceRepository';
|
||||
import type {VoiceRegionRecord, VoiceRegionWithServers, VoiceServerRecord} from '@fluxer/api/src/voice/VoiceModel';
|
||||
|
||||
function toIterable<T>(value: unknown): Array<T> {
|
||||
if (value === null || value === undefined) return [];
|
||||
if (value instanceof Set) return Array.from(value) as Array<T>;
|
||||
if (Array.isArray(value)) return value as Array<T>;
|
||||
return [value as T];
|
||||
}
|
||||
|
||||
const VoiceRegions = defineTable<VoiceRegionRow, 'id'>({
|
||||
name: 'voice_regions',
|
||||
columns: VOICE_REGION_COLUMNS,
|
||||
primaryKey: ['id'],
|
||||
});
|
||||
|
||||
const VoiceServers = defineTable<VoiceServerRow, 'region_id' | 'server_id'>({
|
||||
name: 'voice_servers',
|
||||
columns: VOICE_SERVER_COLUMNS,
|
||||
primaryKey: ['region_id', 'server_id'],
|
||||
});
|
||||
|
||||
const LIST_REGIONS_CQL = VoiceRegions.selectCql();
|
||||
|
||||
const GET_REGION_CQL = VoiceRegions.selectCql({
|
||||
where: VoiceRegions.where.eq('id'),
|
||||
});
|
||||
|
||||
const LIST_SERVERS_FOR_REGION_CQL = VoiceServers.selectCql({
|
||||
where: VoiceServers.where.eq('region_id'),
|
||||
});
|
||||
|
||||
const GET_SERVER_CQL = VoiceServers.selectCql({
|
||||
where: [VoiceServers.where.eq('region_id'), VoiceServers.where.eq('server_id')],
|
||||
});
|
||||
|
||||
export class VoiceRepository implements IVoiceRepository {
|
||||
async listRegions(): Promise<Array<VoiceRegionRecord>> {
|
||||
const rows = await fetchMany<VoiceRegionRow>(LIST_REGIONS_CQL, {});
|
||||
return rows.map((row) => this.mapRegionRow(row));
|
||||
}
|
||||
|
||||
async listRegionsWithServers(): Promise<Array<VoiceRegionWithServers>> {
|
||||
const regions = await this.listRegions();
|
||||
const results: Array<VoiceRegionWithServers> = [];
|
||||
|
||||
for (const region of regions) {
|
||||
const servers = await this.listServersForRegion(region.id);
|
||||
results.push({
|
||||
...region,
|
||||
servers,
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
async getRegion(id: string): Promise<VoiceRegionRecord | null> {
|
||||
const row = await fetchOne<VoiceRegionRow>(GET_REGION_CQL, {id});
|
||||
return row ? this.mapRegionRow(row) : null;
|
||||
}
|
||||
|
||||
async getRegionWithServers(id: string): Promise<VoiceRegionWithServers | null> {
|
||||
const region = await this.getRegion(id);
|
||||
if (!region) {
|
||||
return null;
|
||||
}
|
||||
const servers = await this.listServersForRegion(id);
|
||||
return {...region, servers};
|
||||
}
|
||||
|
||||
async upsertRegion(region: VoiceRegionRecord): Promise<void> {
|
||||
const row: VoiceRegionRow = {
|
||||
id: region.id,
|
||||
name: region.name,
|
||||
emoji: region.emoji,
|
||||
latitude: region.latitude,
|
||||
longitude: region.longitude,
|
||||
is_default: region.isDefault,
|
||||
vip_only: region.restrictions.vipOnly,
|
||||
required_guild_features: new Set(region.restrictions.requiredGuildFeatures),
|
||||
allowed_guild_ids: new Set(Array.from(region.restrictions.allowedGuildIds).map((id) => BigInt(id))),
|
||||
allowed_user_ids: new Set(Array.from(region.restrictions.allowedUserIds).map((id) => BigInt(id))),
|
||||
created_at: region.createdAt ?? new Date(),
|
||||
updated_at: region.updatedAt ?? new Date(),
|
||||
};
|
||||
|
||||
await upsertOne(VoiceRegions.upsertAll(row));
|
||||
}
|
||||
|
||||
async deleteRegion(regionId: string): Promise<void> {
|
||||
const batch = new BatchBuilder();
|
||||
batch.addPrepared(VoiceRegions.deleteByPk({id: regionId}));
|
||||
|
||||
const servers = await this.listServersForRegion(regionId);
|
||||
for (const server of servers) {
|
||||
batch.addPrepared(VoiceServers.deleteByPk({region_id: regionId, server_id: server.serverId}));
|
||||
}
|
||||
|
||||
await batch.execute();
|
||||
}
|
||||
|
||||
async createRegion(region: Omit<VoiceRegionRecord, 'createdAt' | 'updatedAt'>): Promise<VoiceRegionRecord> {
|
||||
const now = new Date();
|
||||
const fullRegion: VoiceRegionRecord = {
|
||||
...region,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
};
|
||||
await this.upsertRegion(fullRegion);
|
||||
return fullRegion;
|
||||
}
|
||||
|
||||
async listServersForRegion(regionId: string): Promise<Array<VoiceServerRecord>> {
|
||||
const rows = await fetchMany<VoiceServerRow>(LIST_SERVERS_FOR_REGION_CQL, {region_id: regionId});
|
||||
return rows.map((row) => this.mapServerRow(row));
|
||||
}
|
||||
|
||||
async listServers(regionId: string): Promise<Array<VoiceServerRecord>> {
|
||||
return this.listServersForRegion(regionId);
|
||||
}
|
||||
|
||||
async getServer(regionId: string, serverId: string): Promise<VoiceServerRecord | null> {
|
||||
const row = await fetchOne<VoiceServerRow>(GET_SERVER_CQL, {region_id: regionId, server_id: serverId});
|
||||
return row ? this.mapServerRow(row) : null;
|
||||
}
|
||||
|
||||
async createServer(server: Omit<VoiceServerRecord, 'createdAt' | 'updatedAt'>): Promise<VoiceServerRecord> {
|
||||
const now = new Date();
|
||||
const fullServer: VoiceServerRecord = {
|
||||
...server,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
};
|
||||
await this.upsertServer(fullServer);
|
||||
return fullServer;
|
||||
}
|
||||
|
||||
async upsertServer(server: VoiceServerRecord): Promise<void> {
|
||||
const row: VoiceServerRow = {
|
||||
region_id: server.regionId,
|
||||
server_id: server.serverId,
|
||||
endpoint: server.endpoint,
|
||||
api_key: server.apiKey,
|
||||
api_secret: server.apiSecret,
|
||||
is_active: server.isActive,
|
||||
vip_only: server.restrictions.vipOnly,
|
||||
required_guild_features: new Set(server.restrictions.requiredGuildFeatures),
|
||||
allowed_guild_ids: new Set(Array.from(server.restrictions.allowedGuildIds).map((id) => BigInt(id))),
|
||||
allowed_user_ids: new Set(Array.from(server.restrictions.allowedUserIds).map((id) => BigInt(id))),
|
||||
created_at: server.createdAt ?? new Date(),
|
||||
updated_at: server.updatedAt ?? new Date(),
|
||||
};
|
||||
|
||||
await upsertOne(VoiceServers.upsertAll(row));
|
||||
}
|
||||
|
||||
async deleteServer(regionId: string, serverId: string): Promise<void> {
|
||||
await deleteOneOrMany(VoiceServers.deleteByPk({region_id: regionId, server_id: serverId}));
|
||||
}
|
||||
|
||||
private mapRegionRow(row: VoiceRegionRow): VoiceRegionRecord {
|
||||
return {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
emoji: row.emoji,
|
||||
latitude: row.latitude,
|
||||
longitude: row.longitude,
|
||||
isDefault: row.is_default ?? false,
|
||||
restrictions: {
|
||||
vipOnly: row.vip_only ?? false,
|
||||
requiredGuildFeatures: new Set(toIterable<string>(row.required_guild_features)),
|
||||
allowedGuildIds: createGuildIDSet(new Set(toIterable<bigint>(row.allowed_guild_ids))),
|
||||
allowedUserIds: createUserIDSet(new Set(toIterable<bigint>(row.allowed_user_ids))),
|
||||
},
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at,
|
||||
};
|
||||
}
|
||||
|
||||
private mapServerRow(row: VoiceServerRow): VoiceServerRecord {
|
||||
return {
|
||||
regionId: row.region_id,
|
||||
serverId: row.server_id,
|
||||
endpoint: row.endpoint,
|
||||
apiKey: row.api_key,
|
||||
apiSecret: row.api_secret,
|
||||
isActive: row.is_active ?? true,
|
||||
restrictions: {
|
||||
vipOnly: row.vip_only ?? false,
|
||||
requiredGuildFeatures: new Set(toIterable<string>(row.required_guild_features)),
|
||||
allowedGuildIds: createGuildIDSet(new Set(toIterable<bigint>(row.allowed_guild_ids))),
|
||||
allowedUserIds: createUserIDSet(new Set(toIterable<bigint>(row.allowed_user_ids))),
|
||||
},
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user