-
Notifications
You must be signed in to change notification settings - Fork 154
/
storage.ts
134 lines (118 loc) · 3.24 KB
/
storage.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { join } from 'path'
import { createStorage, defineDriver, Driver, Storage } from 'unstorage'
import fsDriver from 'unstorage/drivers/fs'
import { promises as FS } from 'graceful-fs'
import { DriverOptions, StorageOptions } from '../types'
import { useDB } from './database'
import { useHooks, logger, useParser } from './'
export interface DocusDriver extends Driver {
init(): Promise<void>
}
export const docusDriver = defineDriver((options: DriverOptions) => {
const { insert, items } = useDB()
const parser = useParser()
const fs = fsDriver(options)
const parseAndIndex = async (key, content) => {
// unify key format
key = key.replace(/\//g, ':')
const document = await parser.parse(key, content)
if (document.extension === '.md') {
const stats = await FS.stat(join(options.base, document.path + document.extension))
document.createdAt = stats.birthtime
document.updatedAt = stats.mtime
}
document.key = key
// use prefix in document path
document.path = `/${options.mountPoint}` + document.path
return insert(document)
}
return {
async init() {
// ensure directory exists
if (!fs.hasItem('')) {
return
}
const keys = await fs.getKeys()
const tasks = keys.map(async key => {
const content = await fs.getItem(key)
await parseAndIndex(key, content)
})
await Promise.all(tasks)
},
hasItem(key) {
return fs.hasItem(key)
},
async getItem(key) {
let item = await items.findOne({ key })
if (!item) {
const content = await fs.getItem(key)
item = await parseAndIndex(key, content)
}
return item
},
async setItem(key, value) {
if (await fs.hasItem(key)) {
await fs.setItem(key, value)
}
await parseAndIndex(key, value)
},
async removeItem(key) {
await items.removeWhere(doc => doc.key === key)
return fs.removeItem(key)
},
getKeys() {
return fs.getKeys()
},
clear() {
return fs.clear()
},
dispose() {
return fs.dispose()
},
watch(callback) {
const { callHook } = useHooks()
return fs.watch(async (event, key) => {
if (event === 'update') {
const content = await fs.getItem(key)
await parseAndIndex(key, content)
}
if (event === 'remove') {
await items.removeWhere(doc => doc.key === key)
}
callHook('docus:storage:updated', { event, key })
callback(event, key)
})
}
}
})
let _storage: Storage
let drivers: DocusDriver[]
export function initStorage(options: StorageOptions) {
drivers = []
_storage = createStorage()
if (!options?.drivers) {
logger.warn('No driver specified for storage')
} else {
drivers = options.drivers.map(options => {
const driver = docusDriver(options) as DocusDriver
_storage.mount(options.mountPoint, driver)
return driver
})
}
return {
storage: _storage,
drivers,
lazyIndex: () => Promise.all(drivers.map(d => d.init()))
}
}
export async function destroyStorage() {
await _storage.dispose()
_storage = null
drivers = null
}
export function useStorage() {
return {
storage: _storage,
drivers
}
}