124 lines
3.6 KiB
TypeScript
124 lines
3.6 KiB
TypeScript
import { type Pixel, type InsertPixel, type CanvasConfig, type InsertCanvasConfig, type UserCooldown, type InsertUserCooldown } from "@shared/schema";
|
|
import { randomUUID } from "crypto";
|
|
import { config } from "./config";
|
|
|
|
export interface IStorage {
|
|
// Pixel operations
|
|
getPixel(x: number, y: number): Promise<Pixel | undefined>;
|
|
getAllPixels(): Promise<Pixel[]>;
|
|
placePixel(pixel: InsertPixel): Promise<Pixel>;
|
|
|
|
// Config operations
|
|
getCanvasConfig(): Promise<CanvasConfig>;
|
|
updateCanvasConfig(config: InsertCanvasConfig): Promise<CanvasConfig>;
|
|
|
|
// User cooldown operations
|
|
getUserCooldown(userId: string): Promise<UserCooldown | undefined>;
|
|
setUserCooldown(cooldown: InsertUserCooldown): Promise<UserCooldown>;
|
|
|
|
// Recent activity
|
|
getRecentPlacements(limit?: number): Promise<Pixel[]>;
|
|
|
|
// Admin operations
|
|
deletePixel(pixelId: string): Promise<void>;
|
|
clearCanvas(): Promise<void>;
|
|
}
|
|
|
|
export class MemStorage implements IStorage {
|
|
private pixels: Map<string, Pixel>;
|
|
private config: CanvasConfig;
|
|
private userCooldowns: Map<string, UserCooldown>;
|
|
|
|
constructor() {
|
|
this.pixels = new Map();
|
|
this.userCooldowns = new Map();
|
|
this.config = {
|
|
id: randomUUID(),
|
|
canvasWidth: config.canvasWidth,
|
|
canvasHeight: config.canvasHeight,
|
|
defaultCooldown: config.defaultCooldown,
|
|
enableAutomaticEvents: config.enableAutomaticEvents,
|
|
eventDuration: config.eventDurationMinutes,
|
|
eventInterval: config.eventIntervalHours,
|
|
|
|
updatedAt: new Date(),
|
|
};
|
|
}
|
|
|
|
private getPixelKey(x: number, y: number): string {
|
|
return `${x},${y}`;
|
|
}
|
|
|
|
async getPixel(x: number, y: number): Promise<Pixel | undefined> {
|
|
return this.pixels.get(this.getPixelKey(x, y));
|
|
}
|
|
|
|
async getAllPixels(): Promise<Pixel[]> {
|
|
return Array.from(this.pixels.values());
|
|
}
|
|
|
|
async placePixel(insertPixel: InsertPixel): Promise<Pixel> {
|
|
const id = randomUUID();
|
|
const pixel: Pixel = {
|
|
...insertPixel,
|
|
id,
|
|
createdAt: new Date(),
|
|
};
|
|
|
|
this.pixels.set(this.getPixelKey(pixel.x, pixel.y), pixel);
|
|
return pixel;
|
|
}
|
|
|
|
async getCanvasConfig(): Promise<CanvasConfig> {
|
|
return this.config;
|
|
}
|
|
|
|
async updateCanvasConfig(configUpdate: InsertCanvasConfig): Promise<CanvasConfig> {
|
|
this.config = {
|
|
...this.config,
|
|
...configUpdate,
|
|
updatedAt: new Date(),
|
|
};
|
|
return this.config;
|
|
}
|
|
|
|
async getUserCooldown(userId: string): Promise<UserCooldown | undefined> {
|
|
return this.userCooldowns.get(userId);
|
|
}
|
|
|
|
async setUserCooldown(insertCooldown: InsertUserCooldown): Promise<UserCooldown> {
|
|
const id = randomUUID();
|
|
const cooldown: UserCooldown = {
|
|
...insertCooldown,
|
|
id,
|
|
lastPlacement: new Date(),
|
|
};
|
|
|
|
this.userCooldowns.set(cooldown.userId, cooldown);
|
|
return cooldown;
|
|
}
|
|
|
|
async getRecentPlacements(limit: number = 10): Promise<Pixel[]> {
|
|
const allPixels = Array.from(this.pixels.values());
|
|
return allPixels
|
|
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
|
|
.slice(0, limit);
|
|
}
|
|
|
|
async deletePixel(pixelId: string): Promise<void> {
|
|
this.pixels.delete(pixelId);
|
|
}
|
|
|
|
async clearCanvas(): Promise<void> {
|
|
this.pixels.clear();
|
|
}
|
|
}
|
|
|
|
// The SQLiteStorage import and usage below is not part of the changes,
|
|
// but is included to ensure the file is complete as per instructions.
|
|
import { SQLiteStorage } from "./sqlite-storage";
|
|
|
|
// Verwende SQLite im Development-Modus, Memory-Storage in Production
|
|
export const storage = process.env.NODE_ENV === 'development'
|
|
? new SQLiteStorage('./dev-database.sqlite')
|
|
: new MemStorage(); |