mirror of
https://github.com/colanode/colanode.git
synced 2025-12-28 16:06:37 +01:00
Add more logs through main services
This commit is contained in:
@@ -7,10 +7,12 @@ import { accountService } from '@/main/services/account-service';
|
||||
import { syncService } from '@/main/services/sync-service';
|
||||
import { notificationService } from '@/main/services/notification-service';
|
||||
import { fileService } from '@/main/services/file-service';
|
||||
import { logService } from '@/main/services/log-service';
|
||||
|
||||
const EVENT_LOOP_INTERVAL = 1000 * 60;
|
||||
|
||||
class Bootstrapper {
|
||||
private readonly logger = logService.createLogger('bootstrapper');
|
||||
private initPromise: Promise<void> | null = null;
|
||||
private eventLoop: NodeJS.Timeout | null = null;
|
||||
|
||||
@@ -27,6 +29,8 @@ class Bootstrapper {
|
||||
}
|
||||
|
||||
private async executeInit() {
|
||||
this.logger.info('Initializing');
|
||||
|
||||
await databaseService.init();
|
||||
await assetService.checkAssets();
|
||||
await serverService.syncServers();
|
||||
@@ -40,6 +44,8 @@ class Bootstrapper {
|
||||
}
|
||||
|
||||
private async executeEventLoop() {
|
||||
this.logger.info('Executing event loop');
|
||||
|
||||
try {
|
||||
await serverService.syncServers();
|
||||
await accountService.syncAccounts();
|
||||
@@ -50,7 +56,7 @@ class Bootstrapper {
|
||||
|
||||
notificationService.checkBadge();
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
this.logger.error('Error executing event loop', error);
|
||||
}
|
||||
|
||||
this.eventLoop = setTimeout(this.executeEventLoop, EVENT_LOOP_INTERVAL);
|
||||
|
||||
@@ -4,6 +4,7 @@ import fs from 'fs';
|
||||
import unzipper from 'unzipper';
|
||||
import { EmojiData } from '@/shared/types/emojis';
|
||||
import { IconData } from '@/shared/types/icons';
|
||||
import { logService } from './log-service';
|
||||
|
||||
type AssetsVersion = {
|
||||
date: string;
|
||||
@@ -15,11 +16,11 @@ const EMOJIS_VERSION = '1.0.0';
|
||||
const ICONS_VERSION = '1.0.0';
|
||||
|
||||
class AssetService {
|
||||
private readonly assetsDir: string;
|
||||
|
||||
constructor() {
|
||||
this.assetsDir = path.join(app.getPath('userData'), 'assets');
|
||||
}
|
||||
private readonly assetsDir: string = path.join(
|
||||
app.getPath('userData'),
|
||||
'assets'
|
||||
);
|
||||
private readonly logger = logService.createLogger('asset-service');
|
||||
|
||||
public async handleAssetRequest(request: Request): Promise<Response> {
|
||||
const url = request.url.replace('asset://', '');
|
||||
@@ -50,6 +51,7 @@ class AssetService {
|
||||
|
||||
public async checkAssets(): Promise<void> {
|
||||
if (!this.shouldUpdateAssets()) {
|
||||
this.logger.debug('Assets are up to date');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -57,6 +59,8 @@ class AssetService {
|
||||
}
|
||||
|
||||
private async updateAssets(): Promise<void> {
|
||||
this.logger.debug('Updating assets');
|
||||
|
||||
await this.updateEmojis();
|
||||
await this.updateIcons();
|
||||
|
||||
@@ -64,6 +68,8 @@ class AssetService {
|
||||
}
|
||||
|
||||
private async updateEmojis(): Promise<void> {
|
||||
this.logger.debug('Updating emojis');
|
||||
|
||||
const emojisZipPath = path.join(this.getAssetsSourcePath(), 'emojis.zip');
|
||||
const emojisDir = path.join(this.assetsDir, 'emojis');
|
||||
if (fs.existsSync(emojisDir)) {
|
||||
@@ -78,6 +84,8 @@ class AssetService {
|
||||
}
|
||||
|
||||
private async updateIcons(): Promise<void> {
|
||||
this.logger.debug('Updating icons');
|
||||
|
||||
const iconsZipPath = path.join(this.getAssetsSourcePath(), 'icons.zip');
|
||||
const iconsDir = path.join(this.assetsDir, 'icons');
|
||||
if (fs.existsSync(iconsDir)) {
|
||||
@@ -94,6 +102,7 @@ class AssetService {
|
||||
private shouldUpdateAssets(): boolean {
|
||||
const assetsVersion = this.readAssetsVersion();
|
||||
if (!assetsVersion) {
|
||||
this.logger.debug('No assets version found, updating assets');
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -106,6 +115,7 @@ class AssetService {
|
||||
private readAssetsVersion(): AssetsVersion | null {
|
||||
const assetsVersionPath = path.join(this.assetsDir, 'version.json');
|
||||
if (!fs.existsSync(assetsVersionPath)) {
|
||||
this.logger.debug('No assets version found');
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,16 @@ import fs from 'fs';
|
||||
import { databaseService } from '@/main/data/database-service';
|
||||
import { httpClient } from '@/shared/lib/http-client';
|
||||
import { getAccountAvatarsDirectoryPath } from '@/main/utils';
|
||||
import { logService } from '@/main/services/log-service';
|
||||
|
||||
class AvatarService {
|
||||
private readonly logger = logService.createLogger('avatar-service');
|
||||
|
||||
public async handleAvatarRequest(request: Request): Promise<Response> {
|
||||
const url = request.url.replace('avatar://', '');
|
||||
const [accountId, avatarId] = url.split('/');
|
||||
if (!accountId || !avatarId) {
|
||||
this.logger.warn(`Invalid avatar request url: ${url}`);
|
||||
return new Response(null, { status: 400 });
|
||||
}
|
||||
|
||||
@@ -22,6 +26,9 @@ class AvatarService {
|
||||
return net.fetch(avatarLocalUrl);
|
||||
}
|
||||
|
||||
this.logger.debug(
|
||||
`Downloading avatar ${avatarId} for account ${accountId}`
|
||||
);
|
||||
// Download the avatar file if it doesn't exist
|
||||
const credentials = await databaseService.appDatabase
|
||||
.selectFrom('accounts')
|
||||
@@ -31,6 +38,7 @@ class AvatarService {
|
||||
.executeTakeFirst();
|
||||
|
||||
if (!credentials) {
|
||||
this.logger.warn(`Account ${accountId} not found`);
|
||||
return new Response(null, { status: 404 });
|
||||
}
|
||||
|
||||
@@ -41,6 +49,9 @@ class AvatarService {
|
||||
});
|
||||
|
||||
if (response.status !== 200 || !response.data) {
|
||||
this.logger.warn(
|
||||
`Failed to download avatar ${avatarId} for account ${accountId}`
|
||||
);
|
||||
return new Response(null, { status: 404 });
|
||||
}
|
||||
|
||||
@@ -55,10 +66,16 @@ class AvatarService {
|
||||
|
||||
fileStream.on('finish', async () => {
|
||||
// Ensure the file is written before trying to fetch it
|
||||
this.logger.debug(
|
||||
`Avatar ${avatarId} for account ${accountId} downloaded`
|
||||
);
|
||||
resolve(net.fetch(avatarLocalUrl));
|
||||
});
|
||||
|
||||
fileStream.on('error', (err) => {
|
||||
this.logger.warn(
|
||||
`Failed to download avatar ${avatarId} for account ${accountId}`
|
||||
);
|
||||
reject(new Response(null, { status: 500, statusText: err.message }));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import { CommandInput } from '@/shared/commands';
|
||||
|
||||
import { logService } from '@/main/services/log-service';
|
||||
import { CommandMap } from '@/shared/commands';
|
||||
import { commandHandlerMap } from '@/main/commands';
|
||||
import { CommandHandler } from '@/main/types';
|
||||
|
||||
class CommandService {
|
||||
private readonly logger = logService.createLogger('command-service');
|
||||
|
||||
public async executeCommand<T extends CommandInput>(
|
||||
input: T
|
||||
): Promise<CommandMap[T['type']]['output']> {
|
||||
this.logger.debug(`Executing command: ${input.type}`);
|
||||
|
||||
const handler = commandHandlerMap[
|
||||
input.type
|
||||
] as unknown as CommandHandler<T>;
|
||||
|
||||
if (!handler) {
|
||||
this.logger.warn(`No handler found for command type: ${input.type}`);
|
||||
throw new Error(`No handler found for command type: ${input.type}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
} from '@colanode/core';
|
||||
import { eventBus } from '@/shared/lib/event-bus';
|
||||
import { serverService } from '@/main/services/server-service';
|
||||
import { logService } from '@/main/services/log-service';
|
||||
|
||||
type WorkspaceFileState = {
|
||||
isUploading: boolean;
|
||||
@@ -25,7 +26,8 @@ type WorkspaceFileState = {
|
||||
};
|
||||
|
||||
class FileService {
|
||||
private fileStates: Map<string, WorkspaceFileState> = new Map();
|
||||
private readonly logger = logService.createLogger('file-service');
|
||||
private readonly fileStates: Map<string, WorkspaceFileState> = new Map();
|
||||
|
||||
constructor() {
|
||||
eventBus.subscribe((event) => {
|
||||
@@ -41,6 +43,7 @@ class FileService {
|
||||
const url = request.url.replace('local-file://', '');
|
||||
const [userId, file] = url.split('/');
|
||||
if (!userId || !file) {
|
||||
this.logger.warn(`Invalid file request url: ${url}`);
|
||||
return new Response(null, { status: 400 });
|
||||
}
|
||||
|
||||
@@ -52,6 +55,7 @@ class FileService {
|
||||
return net.fetch(fileUrl);
|
||||
}
|
||||
|
||||
this.logger.warn(`File ${file} not found for user ${userId}`);
|
||||
return new Response(null, { status: 404 });
|
||||
}
|
||||
|
||||
@@ -77,18 +81,26 @@ class FileService {
|
||||
filesDir,
|
||||
`${fileId}_${uploadId}${fileExtension}`
|
||||
);
|
||||
|
||||
this.logger.debug(
|
||||
`Copying file ${filePath} to ${destinationFilePath} for user ${userId}`
|
||||
);
|
||||
fs.copyFileSync(filePath, destinationFilePath);
|
||||
}
|
||||
|
||||
public openFile(userId: string, id: string, extension: string): void {
|
||||
const filesDir = getWorkspaceFilesDirectoryPath(userId);
|
||||
const filePath = path.join(filesDir, `${id}${extension}`);
|
||||
|
||||
this.logger.debug(`Opening file ${filePath} for user ${userId}`);
|
||||
shell.openPath(filePath);
|
||||
}
|
||||
|
||||
public deleteFile(userId: string, id: string, extension: string): void {
|
||||
const filesDir = getWorkspaceFilesDirectoryPath(userId);
|
||||
const filePath = path.join(filesDir, `${id}${extension}`);
|
||||
|
||||
this.logger.debug(`Deleting file ${filePath} for user ${userId}`);
|
||||
fs.rmSync(filePath, { force: true });
|
||||
}
|
||||
|
||||
@@ -105,6 +117,8 @@ class FileService {
|
||||
const stats = fs.statSync(filePath);
|
||||
const type = extractFileType(mimeType);
|
||||
|
||||
this.logger.debug(`Getting file metadata for ${filePath}`);
|
||||
|
||||
return {
|
||||
path: filePath,
|
||||
mimeType,
|
||||
@@ -116,6 +130,8 @@ class FileService {
|
||||
}
|
||||
|
||||
public async syncFiles() {
|
||||
this.logger.info('Syncing files');
|
||||
|
||||
const workspaces = await databaseService.appDatabase
|
||||
.selectFrom('workspaces')
|
||||
.select(['user_id'])
|
||||
@@ -139,6 +155,9 @@ class FileService {
|
||||
const fileState = this.fileStates.get(userId)!;
|
||||
if (fileState.isUploading) {
|
||||
fileState.isUploadScheduled = true;
|
||||
this.logger.debug(
|
||||
`Uploading files for user ${userId} is in progress, scheduling upload`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -146,7 +165,7 @@ class FileService {
|
||||
try {
|
||||
await this.uploadWorkspaceFiles(userId);
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
this.logger.error(`Error uploading files for user ${userId}`, error);
|
||||
} finally {
|
||||
fileState.isUploading = false;
|
||||
if (fileState.isUploadScheduled) {
|
||||
@@ -169,6 +188,9 @@ class FileService {
|
||||
const fileState = this.fileStates.get(userId)!;
|
||||
if (fileState.isDownloading) {
|
||||
fileState.isDownloadScheduled = true;
|
||||
this.logger.debug(
|
||||
`Downloading files for user ${userId} is in progress, scheduling download`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -176,7 +198,7 @@ class FileService {
|
||||
try {
|
||||
await this.downloadWorkspaceFiles(userId);
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
this.logger.error(`Error downloading files for user ${userId}`, error);
|
||||
} finally {
|
||||
fileState.isDownloading = false;
|
||||
if (fileState.isDownloadScheduled) {
|
||||
@@ -187,6 +209,8 @@ class FileService {
|
||||
}
|
||||
|
||||
private async uploadWorkspaceFiles(userId: string): Promise<void> {
|
||||
this.logger.debug(`Uploading files for user ${userId}`);
|
||||
|
||||
if (!this.fileStates.has(userId)) {
|
||||
this.fileStates.set(userId, {
|
||||
isUploading: false,
|
||||
@@ -199,6 +223,9 @@ class FileService {
|
||||
const fileState = this.fileStates.get(userId)!;
|
||||
if (fileState.isUploading) {
|
||||
fileState.isUploadScheduled = true;
|
||||
this.logger.debug(
|
||||
`Uploading files for user ${userId} is in progress, scheduling upload`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -233,6 +260,7 @@ class FileService {
|
||||
.executeTakeFirst();
|
||||
|
||||
if (!workspace) {
|
||||
this.logger.warn(`Workspace not found for user ${userId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -354,6 +382,7 @@ class FileService {
|
||||
.executeTakeFirst();
|
||||
|
||||
if (!workspace) {
|
||||
this.logger.warn(`Workspace not found for user ${userId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,11 @@ import { MutationInput } from '@/shared/mutations';
|
||||
import { MutationMap } from '@/shared/mutations';
|
||||
import { mutationHandlerMap } from '@/main/mutations';
|
||||
import { MutationHandler } from '@/main/types';
|
||||
import { logService } from '@/main/services/log-service';
|
||||
|
||||
class MutationService {
|
||||
private readonly logger = logService.createLogger('mutation-service');
|
||||
|
||||
public async executeMutation<T extends MutationInput>(
|
||||
input: T
|
||||
): Promise<MutationMap[T['type']]['output']> {
|
||||
@@ -12,7 +15,10 @@ class MutationService {
|
||||
input.type
|
||||
] as unknown as MutationHandler<T>;
|
||||
|
||||
this.logger.debug(`Executing mutation: ${input.type}`);
|
||||
|
||||
if (!handler) {
|
||||
this.logger.warn(`No handler found for mutation type: ${input.type}`);
|
||||
throw new Error(`No handler found for mutation type: ${input.type}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@ import { queryHandlerMap } from '@/main/queries';
|
||||
import { eventBus } from '@/shared/lib/event-bus';
|
||||
import { Event } from '@/shared/types/events';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { logService } from '@/main/services/log-service';
|
||||
|
||||
class QueryService {
|
||||
private readonly logger = logService.createLogger('query-service');
|
||||
private readonly subscribedQueries: Map<string, SubscribedQuery<QueryInput>> =
|
||||
new Map();
|
||||
|
||||
@@ -26,7 +28,15 @@ class QueryService {
|
||||
public async executeQuery<T extends QueryInput>(
|
||||
input: T
|
||||
): Promise<QueryMap[T['type']]['output']> {
|
||||
this.logger.debug(`Executing query: ${input.type}`);
|
||||
|
||||
const handler = queryHandlerMap[input.type] as unknown as QueryHandler<T>;
|
||||
|
||||
if (!handler) {
|
||||
this.logger.warn(`No handler found for query type: ${input.type}`);
|
||||
throw new Error(`No handler found for query type: ${input.type}`);
|
||||
}
|
||||
|
||||
const result = await handler.handleQuery(input);
|
||||
return result;
|
||||
}
|
||||
@@ -35,11 +45,18 @@ class QueryService {
|
||||
id: string,
|
||||
input: T
|
||||
): Promise<QueryMap[T['type']]['output']> {
|
||||
this.logger.debug(`Executing query and subscribing: ${input.type}`);
|
||||
|
||||
if (this.subscribedQueries.has(id)) {
|
||||
return this.subscribedQueries.get(id)!.result;
|
||||
}
|
||||
|
||||
const handler = queryHandlerMap[input.type] as unknown as QueryHandler<T>;
|
||||
if (!handler) {
|
||||
this.logger.warn(`No handler found for query type: ${input.type}`);
|
||||
throw new Error(`No handler found for query type: ${input.type}`);
|
||||
}
|
||||
|
||||
const result = await handler.handleQuery(input);
|
||||
this.subscribedQueries.set(id, {
|
||||
input,
|
||||
@@ -49,6 +66,7 @@ class QueryService {
|
||||
}
|
||||
|
||||
public unsubscribeQuery(id: string) {
|
||||
this.logger.debug(`Unsubscribing query: ${id}`);
|
||||
this.subscribedQueries.delete(id);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user