Skip to content

Commit

Permalink
refactor: bring window into nest app & restructure main functions and…
Browse files Browse the repository at this point in the history
… remove unused modules

- Migrate utility functions to `functions` directory for better
  organization.
- Remove obsolete `store` related files to streamline codebase.
- Update imports and mocks across the codebase to reflect new
  directory structure.
- Replace `Store` usage with a more persistent and reliable
  settings storage mechanism using `WindowSetting` schema.
- Enhance main window lifecycle management in `MainWindow` service.
- Update application bootstrap process with `bootstrapNestApplication`.
  • Loading branch information
🎲 committed Dec 21, 2024
1 parent a005078 commit ef6ea41
Show file tree
Hide file tree
Showing 27 changed files with 389 additions and 617 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTNG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The following is a brief overview of the project structure:
- `src/main` - Contains the main process code.
- `src/main/index.ts` - Contains the main entry point for the application.
- `src/main/router.ts` - Contains the trpc-router for the main process. This calls the bootstrap function to create the NestJS App and then exposes trpc procedures to the renderer.
- `src/main/app.ts` - Contains the entrypoint for the NestJS application.
- `src/main/bootstrap.ts` - Contains the entrypoint for the NestJS application.
- `src/renderer` - Contains the renderer process code.
- `src/renderer/index.html` - Contains the main HTML file for the renderer process.
- `src/renderer/main.tsx` - Contains the main entry point for the renderer process. This creates the React application and mounts it to the DOM.
Expand Down
2 changes: 1 addition & 1 deletion electron-builder.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
appId: dcs-dropzone
appId: com.flyingdice.dcsdropzonemodmanager
productName: DCS DROPZONE - Community Mod Manager
directories:
buildResources: build
Expand Down
43 changes: 23 additions & 20 deletions src/main/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {
Logger,
Module,
OnApplicationBootstrap,
OnApplicationShutdown
OnApplicationShutdown,
OnModuleInit
} from '@nestjs/common'
import { LifecycleManager } from './manager/lifecycle-manager.service'
import { SettingsManager } from './manager/settings.manager'
Expand All @@ -14,7 +15,7 @@ import { RegistryService } from './services/registry.service'
import { WriteDirectoryService } from './services/write-directory.service'
import { VariablesService } from './services/variables.service'
import { InjectConnection, MongooseModule } from '@nestjs/mongoose'
import { MongooseFactory } from './mongoose.factory'
import { MongooseFactory } from './utils/mongoose.factory'
import { Config, ConfigSchema } from './schemas/config.schema'
import { Subscription, SubscriptionSchema } from './schemas/subscription.schema'
import { Release, ReleaseSchema } from './schemas/release.schema'
Expand All @@ -34,6 +35,8 @@ import { UninstallBatManager } from './manager/uninstall-bat.manager'
import { ApplicationClosingEvent } from './events/application-closing.event'
import { ApplicationReadyEvent } from './events/application-ready.event'
import { ScheduleModule } from '@nestjs/schedule'
import { MainWindow } from './windows/main.window'
import { WindowSetting, WindowSettingSchema } from './schemas/window-setting'

@Module({
imports: [
Expand All @@ -52,25 +55,28 @@ import { ScheduleModule } from '@nestjs/schedule'
{ name: Subscription.name, schema: SubscriptionSchema },
{ name: Release.name, schema: ReleaseSchema },
{ name: ReleaseAsset.name, schema: ReleaseAssetSchema },
{ name: AssetTask.name, schema: AssetTaskSchema }
])
{ name: AssetTask.name, schema: AssetTaskSchema },
{ name: WindowSetting.name, schema: WindowSettingSchema }
]),
MongooseModule
],
providers: [
SubscriptionService,
ReleaseService,
SettingsService,
FsService,
SettingsManager,
LifecycleManager,
MainWindow,
RegistryService,
ReleaseService,
SettingsManager,
SettingsService,
SubscriptionManager,
SubscriptionService,
TaskManager,
LifecycleManager,
WriteDirectoryService,
UninstallBatManager,
VariablesService,
UninstallBatManager
WriteDirectoryService
]
})
export class AppModule implements OnApplicationBootstrap, OnApplicationShutdown {
export class AppModule implements OnModuleInit, OnApplicationBootstrap, OnApplicationShutdown {
private readonly logger = new Logger(AppModule.name)

@InjectConnection()
Expand All @@ -82,12 +88,15 @@ export class AppModule implements OnApplicationBootstrap, OnApplicationShutdown
@Inject(ConfigService)
private readonly configService: ConfigService<MainConfig>

@Log()
async onModuleInit() {
this.logger.log('Module is being initialized')
}

@Log()
async onApplicationBootstrap() {
this.logger.log('Application is starting...')

await this.initDatabase()

this.logger.log(
'Application is started, firing ApplicationReadyEvent once 7zip and rclone are ready...'
)
Expand All @@ -111,12 +120,6 @@ export class AppModule implements OnApplicationBootstrap, OnApplicationShutdown
this.logger.log('Rclone is ready')
}

private async initDatabase() {
this.logger.debug('Waiting for database connection...')
await this.connection.asPromise()
this.logger.log('Database is ready')
}

@Log()
async onApplicationShutdown() {
this.logger.debug('Shutting down app')
Expand Down
19 changes: 0 additions & 19 deletions src/main/app.ts

This file was deleted.

77 changes: 0 additions & 77 deletions src/main/create-main-window.ts

This file was deleted.

45 changes: 45 additions & 0 deletions src/main/functions/bootstrap-nest-application.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { NestFactory } from '@nestjs/core'
import { AppModule } from '../app.module'
import { WinstonModule } from 'nest-winston'
import { consoleTransport, fileTransport } from '../logging'
import { Logger, ShutdownSignal } from '@nestjs/common'
import { BrowserWindow } from 'electron'
import { join } from 'node:path'

export async function bootstrapNestApplication() {
const logger = new Logger('bootstrap')
logger.log('Bootstrapping application')
const splashScreen = new BrowserWindow({
width: 1050,
height: 600,
show: true,
frame: false,
alwaysOnTop: false
})
await splashScreen.loadFile(join(__dirname, '../../resources/splash.png'))
splashScreen.setTitle('DCS Dropzone Mod Manager')

try {
logger.log('Creating application context')
const applicationContext = await NestFactory.createApplicationContext(AppModule, {
abortOnError: false,
logger: WinstonModule.createLogger({
level: 'silly',
transports: [consoleTransport, fileTransport]
})
})
applicationContext.enableShutdownHooks([ShutdownSignal.SIGTERM, ShutdownSignal.SIGINT])

logger.log('Initializing application context')
await applicationContext.init()

logger.log('Application context initialized, closing splash screen')
splashScreen.close()

return applicationContext
} catch (e) {
splashScreen.close()
logger.error('Failed to bootstrap application', e)
throw e
}
}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getUrlPartsForDownload } from '../functions/getUrlPartsForDownload'
import { getUrlPartsForDownload } from './getUrlPartsForDownload'
import { _7zip } from '../tools/7zip'
import { extname } from 'node:path'
import { EntryIndexVersionsItemAssetsItem } from '../../lib/client'
Expand Down
63 changes: 30 additions & 33 deletions src/main/functions/onMainWindowMovement.test.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,60 @@
import { describe, it, expect, vi } from 'vitest'
import { BrowserWindow } from 'electron'
import { onBrowserWindowMovement } from './onMainWindowMovement'
import { Store } from '../utils/store'

describe('onBrowserWindowMovement', () => {
it('stores window size and position when window is moved', async () => {
it('saves window position and size correctly', async () => {
const mockWindow = {
getSize: vi.fn().mockReturnValue([800, 600]),
getPosition: vi.fn().mockReturnValue([100, 100]),
getSize: vi.fn().mockReturnValue([1024, 768]),
getPosition: vi.fn().mockReturnValue([200, 150]),
isMaximized: vi.fn().mockReturnValue(false)
} as unknown as BrowserWindow

const mockStore = {
set: vi.fn(),
write: vi.fn().mockResolvedValue(undefined)
} as unknown as Store<number>
const saveWindowPosition = vi.fn().mockResolvedValue(undefined)

const handler = onBrowserWindowMovement(mockWindow, mockStore)
const handler = onBrowserWindowMovement(mockWindow, saveWindowPosition)
await handler()

expect(mockStore.set).toHaveBeenCalledWith('width', 800)
expect(mockStore.set).toHaveBeenCalledWith('height', 600)
expect(mockStore.set).toHaveBeenCalledWith('x', 100)
expect(mockStore.set).toHaveBeenCalledWith('y', 100)
expect(mockStore.set).toHaveBeenCalledWith('maximized', 0)
expect(mockStore.write).toHaveBeenCalled()
expect(saveWindowPosition).toHaveBeenCalledWith({
width: 1024,
height: 768,
x: 200,
y: 150,
maximized: false
})
})

it('stores maximized state when window is maximized', async () => {
it('saves maximized state correctly', async () => {
const mockWindow = {
getSize: vi.fn().mockReturnValue([800, 600]),
getPosition: vi.fn().mockReturnValue([100, 100]),
getSize: vi.fn().mockReturnValue([1024, 768]),
getPosition: vi.fn().mockReturnValue([200, 150]),
isMaximized: vi.fn().mockReturnValue(true)
} as unknown as BrowserWindow

const mockStore = {
set: vi.fn(),
write: vi.fn().mockResolvedValue(undefined)
} as unknown as Store<number>
const saveWindowPosition = vi.fn().mockResolvedValue(undefined)

const handler = onBrowserWindowMovement(mockWindow, mockStore)
const handler = onBrowserWindowMovement(mockWindow, saveWindowPosition)
await handler()

expect(mockStore.set).toHaveBeenCalledWith('maximized', 1)
expect(saveWindowPosition).toHaveBeenCalledWith({
width: 1024,
height: 768,
x: 200,
y: 150,
maximized: true
})
})

it('handles errors during store write', async () => {
it('handles errors during saveWindowPosition call', async () => {
const mockWindow = {
getSize: vi.fn().mockReturnValue([800, 600]),
getPosition: vi.fn().mockReturnValue([100, 100]),
getSize: vi.fn().mockReturnValue([1024, 768]),
getPosition: vi.fn().mockReturnValue([200, 150]),
isMaximized: vi.fn().mockReturnValue(false)
} as unknown as BrowserWindow

const mockStore = {
set: vi.fn(),
write: vi.fn().mockRejectedValue(new Error('Write failed'))
} as unknown as Store<number>
const saveWindowPosition = vi.fn().mockRejectedValue(new Error('Save failed'))

const handler = onBrowserWindowMovement(mockWindow, mockStore)
await expect(handler()).rejects.toThrow('Write failed')
const handler = onBrowserWindowMovement(mockWindow, saveWindowPosition)
await expect(handler()).rejects.toThrow('Save failed')
})
})
21 changes: 12 additions & 9 deletions src/main/functions/onMainWindowMovement.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { BrowserWindow } from 'electron'
import { Store } from '../utils/store'

export function onBrowserWindowMovement(window: BrowserWindow, store: Store<number>) {
export function onBrowserWindowMovement(
window: BrowserWindow,
saveWindowPosition: ({}: {
width: number
height: number
x: number
y: number
maximized: boolean
}) => Promise<any>
) {
return async function () {
const [width, height] = window.getSize()
const [x, y] = window.getPosition()
const isMaximized = window.isMaximized()
store.set('width', width)
store.set('height', height)
store.set('x', x)
store.set('y', y)
store.set('maximized', isMaximized ? 1 : 0)
await store.write()
const maximized = window.isMaximized()
await saveWindowPosition({ width, height, x, y, maximized })
}
}
Loading

0 comments on commit ef6ea41

Please sign in to comment.