place_maxlan/server/storage.ts
freesemar93 7968b56976 Allow configuration through a file and export images automatically
Introduce a configuration file for all settings, remove the web-based config editor, fix the grid display, and add automatic hourly PNG exports.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 0385ea33-cde8-4bbd-8fce-8d192d30eb41
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/870d08ce-da3b-4822-9874-c2fe2b7628b1/0385ea33-cde8-4bbd-8fce-8d192d30eb41/Zffw2vY
2025-08-18 12:20:13 +00:00

106 lines
3.0 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[]>;
}
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,
showGridByDefault: config.showGridByDefault,
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);
}
}
export const storage = new MemStorage();