Skip to content

Commit

Permalink
chore: refactor project structure
Browse files Browse the repository at this point in the history
  • Loading branch information
AriTheElk committed Dec 18, 2024
1 parent fd299dd commit 245d790
Show file tree
Hide file tree
Showing 13 changed files with 165 additions and 142 deletions.
49 changes: 49 additions & 0 deletions src/Backgrounder/Backgrounder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { ImagePicker } from '../ImagePicker'

import { BackgrounderLane } from './BackgrounderLane'
import { BackgrounderLaneProps } from './types'

/**
* General purpose background job runner :)
*
* This is used mostly to alleviate the main thread from
* doing too much work at once. Things like indexing,
* image processing, or other long-running tasks can be
* run in the background.
*
* It's a FIFO queue, so jobs are run in the order they
* are enqueued.
*/
export class Backgrounder {
public lanes: Record<string, BackgrounderLane> = {}

constructor(public plugin: ImagePicker) {}

log = (...args: unknown[]) => {
this.plugin.log('Backgrounder -> ', ...args)
}

createLane = (lane: Omit<BackgrounderLaneProps, 'queue'>) => {
this.lanes[lane.type] = new BackgrounderLane(this.plugin, lane)
}

deleteLane = (type: string) => {
delete this.lanes[type]
}

stop = (type: string) => {
if (this.lanes[type]) {
this.lanes[type].clear()
this.log('Stopped lane:', type)
} else {
this.log('Lane not found:', type)
}
}

stopAll = () => {
for (const lane of Object.values(this.lanes)) {
lane.clear()
}
this.log('Stopped all lanes')
}
}
101 changes: 7 additions & 94 deletions src/backend/Backgrounder.ts → src/Backgrounder/BackgrounderLane.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,11 @@
import ImagePicker from 'src/main'
import { v4 } from 'uuid'

import { ImagePicker } from '../ImagePicker'

export interface BackgrounderJob {
/**
* Internally used UUID for the job
*/
id: string
/**
* The type of job, in a small string.
*
* This is used as a "unique" identifier for the job.
* If you run it in a lane with `unique: true`, only
* one job of this type will be in the queue at a time.
*/
type: string
/**
* The action that will be run when the job is executed
*/
action: () => void | Promise<void>
/**
* If true, the job will be run immediately if the lane is free
*/
eager?: boolean
}

export type BackgrounderQueue = BackgrounderJob[]

export interface BackgrounderLaneProps {
type: string
queue: BackgrounderQueue
/**
* The time to wait between jobs in milliseconds
*/
sleep: number
/**
* If true, only one job of this type can be in the queue at a time
*/
unique: boolean
/**
* Determines which job to keep when enqueuing a unique job
*
* 'first' keeps the existing job and ignores the new one
* 'last' keeps the new job and removes the existing one
*
* @default 'first'
*/
uniqueKeep: 'first' | 'last'
}
import {
BackgrounderQueue,
BackgrounderLaneProps,
BackgrounderJob,
} from './types'

export class BackgrounderLane {
private plugin: ImagePicker
Expand All @@ -58,7 +16,7 @@ export class BackgrounderLane {
private queue: BackgrounderQueue
private sleepTime: number = 0

log = (...args: any[]) => {
log = (...args: unknown[]) => {
this.plugin.log(`Lane [${this.type}] -> `, ...args)
}

Expand Down Expand Up @@ -152,48 +110,3 @@ export class BackgrounderLane {
this.log('Cleared queue')
}
}

/**
* General purpose background job runner :)
*
* This is used mostly to alleviate the main thread from
* doing too much work at once. Things like indexing,
* image processing, or other long-running tasks can be
* run in the background.
*
* It's a FIFO queue, so jobs are run in the order they
* are enqueued.
*/
export class Backgrounder {
public lanes: Record<string, BackgrounderLane> = {}

constructor(public plugin: ImagePicker) {}

log = (...args: any[]) => {
this.plugin.log('Backgrounder -> ', ...args)
}

createLane = (lane: Omit<BackgrounderLaneProps, 'queue'>) => {
this.lanes[lane.type] = new BackgrounderLane(this.plugin, lane)
}

deleteLane = (type: string) => {
delete this.lanes[type]
}

stop = (type: string) => {
if (this.lanes[type]) {
this.lanes[type].clear()
this.log('Stopped lane:', type)
} else {
this.log('Lane not found:', type)
}
}

stopAll = () => {
for (const lane of Object.values(this.lanes)) {
lane.clear()
}
this.log('Stopped all lanes')
}
}
2 changes: 2 additions & 0 deletions src/Backgrounder/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Backgrounder'
export * from './types'
46 changes: 46 additions & 0 deletions src/Backgrounder/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export interface BackgrounderJob {
/**
* Internally used UUID for the job
*/
id: string
/**
* The type of job, in a small string.
*
* This is used as a "unique" identifier for the job.
* If you run it in a lane with `unique: true`, only
* one job of this type will be in the queue at a time.
*/
type: string
/**
* The action that will be run when the job is executed
*/
action: () => void | Promise<void>
/**
* If true, the job will be run immediately if the lane is free
*/
eager?: boolean
}

export type BackgrounderQueue = BackgrounderJob[]

export interface BackgrounderLaneProps {
type: string
queue: BackgrounderQueue
/**
* The time to wait between jobs in milliseconds
*/
sleep: number
/**
* If true, only one job of this type can be in the queue at a time
*/
unique: boolean
/**
* Determines which job to keep when enqueuing a unique job
*
* 'first' keeps the existing job and ignores the new one
* 'last' keeps the new job and removes the existing one
*
* @default 'first'
*/
uniqueKeep: 'first' | 'last'
}
6 changes: 3 additions & 3 deletions src/ImagePicker.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { App, Plugin, PluginManifest, TFile, WorkspaceLeaf } from 'obsidian'
import { pick } from 'lodash'

import { Indexer } from './backend/Indexer'
import { Indexer } from './Indexer'
import {
ImagePickerSettings,
ImagePickerSettingTab,
Expand All @@ -12,7 +12,7 @@ import {
VALID_IMAGE_EXTENSIONS,
VIEW_TYPE_IMAGE_PICKER,
} from './constants'
import { Backgrounder } from './backend/Backgrounder'
import { Backgrounder } from './Backgrounder'

export class ImagePicker extends Plugin {
settings: ImagePickerSettings
Expand All @@ -27,7 +27,7 @@ export class ImagePicker extends Plugin {
super(app, manifest)
}

log = (...args: any[]) => {
log = (...args: unknown[]) => {
if (this.settings?.debugMode) {
console.log('ImagePicker -> ', ...args)
}
Expand Down
51 changes: 10 additions & 41 deletions src/backend/Indexer.ts → src/Indexer/Indexer.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,22 @@
import { TFile } from 'obsidian'
import { debounce, merge } from 'lodash'
import { v4 } from 'uuid'
import Dexie from 'dexie'

import {
fetchImageFile,
getImageFileSize,
imageToArrayBuffer,
makeThumbnail,
} from '../utils'
import ImagePicker from '../main'
import { ImagePicker } from '../ImagePicker'

export interface IndexerRoot {
[path: string]: IndexerNode
}

export interface IndexerNode
extends Pick<TFile, 'basename' | 'extension' | 'stat' | 'path' | 'name'> {
uri: string
thumbnail?: string
}

export interface AbstractIndexerRoot {
[path: string]: AbstractIndexerNode
}

export interface AbstractIndexerNode extends Omit<IndexerNode, 'thumbnail'> {
thumbnail: Thumbnail
}

export interface Thumbnail {
id: string
data: string
}

class IndexerDB extends Dexie {
index: Dexie.Table<IndexerNode, string>
thumbnails: Dexie.Table<Thumbnail, string>

constructor() {
super('IndexerDB')
this.version(1).stores({
index: 'path',
thumbnails: 'id',
})
this.index = this.table('index')
this.thumbnails = this.table('thumbnails')
}
}
import {
IndexerNode,
Thumbnail,
IndexerRoot,
AbstractIndexerRoot,
AbstractIndexerNode,
} from './types'
import { IndexerDB } from './IndexerDB'

export class Indexer {
private memory: IndexerRoot = {}
Expand Down Expand Up @@ -77,7 +46,7 @@ export class Indexer {
this.db = new IndexerDB()
}

log = (...args: any[]) => {
log = (...args: unknown[]) => {
this.plugin.log('Indexer -> ', ...args)
}

Expand Down
18 changes: 18 additions & 0 deletions src/Indexer/IndexerDB.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Dexie from 'dexie'

import { IndexerNode, Thumbnail } from './types'

export class IndexerDB extends Dexie {
index: Dexie.Table<IndexerNode, string>
thumbnails: Dexie.Table<Thumbnail, string>

constructor() {
super('ImagePicker')
this.version(1).stores({
index: 'path',
thumbnails: 'id',
})
this.index = this.table('index')
this.thumbnails = this.table('thumbnails')
}
}
2 changes: 2 additions & 0 deletions src/Indexer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Indexer'
export * from './types'
24 changes: 24 additions & 0 deletions src/Indexer/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { type TFile } from 'obsidian'

export interface IndexerRoot {
[path: string]: IndexerNode
}

export interface IndexerNode
extends Pick<TFile, 'basename' | 'extension' | 'stat' | 'path' | 'name'> {
uri: string
thumbnail?: string
}

export interface AbstractIndexerRoot {
[path: string]: AbstractIndexerNode
}

export interface AbstractIndexerNode extends Omit<IndexerNode, 'thumbnail'> {
thumbnail: Thumbnail
}

export interface Thumbnail {
id: string
data: string
}
2 changes: 1 addition & 1 deletion src/client/ImagePickerContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createContext, useContext } from 'react'
import { App } from 'obsidian'

import ImagePicker from '../main'
import { IndexerNode } from '../backend/Indexer'
import { IndexerNode } from '../Indexer'

export interface ImagePickerContextType {
app: App
Expand Down
2 changes: 1 addition & 1 deletion src/client/ImagePickerView/ImagePickerView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
setGridHeight,
tokenizeSearchQuery,
} from '../../utils'
import { AbstractIndexerNode, IndexerNode } from '../../backend/Indexer'
import { AbstractIndexerNode, IndexerNode } from '../../Indexer'
import { useApp, useFiles, usePlugin } from '../ImagePickerContext'
import { Thumbnail } from '../Thumbnail'

Expand Down
2 changes: 1 addition & 1 deletion src/client/Thumbnail.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FC, useCallback, useEffect, useRef, useState } from 'react'

import { AbstractIndexerNode, IndexerNode } from '../backend/Indexer'
import { AbstractIndexerNode, IndexerNode } from '../Indexer'

import { usePlugin } from './ImagePickerContext'

Expand Down
2 changes: 1 addition & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { readAndCompressImage } from 'browser-image-resizer'

import { AbstractIndexerNode, IndexerNode } from './backend/Indexer'
import { AbstractIndexerNode, IndexerNode } from './Indexer'
import { queryTokens, ROW_HEIGHT } from './constants'

export const getSizeInKb = (size: number): number => {
Expand Down

0 comments on commit 245d790

Please sign in to comment.