-
Notifications
You must be signed in to change notification settings - Fork 0
/
storage.js
141 lines (119 loc) · 3.03 KB
/
storage.js
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
135
136
137
138
139
140
141
const debug = require('debug')('ara-filesystem:storage')
const storage = require('ara-contracts/storage')
const ras = require('random-access-storage')
const raf = require('random-access-file')
const unixify = require('unixify')
const {
writeToStaged,
readFromStaged,
hasStaged
} = require('./commit')
const {
METADATA_TREE_INDEX,
METADATA_SIGNATURES_INDEX,
METADATA_TREE_NAME: mTreeName,
METADATA_SIGNATURES_NAME: mSigName
} = require('./constants')
const {
resolve,
basename
} = require('path')
function defaultStorage(identity, writable = false, storageFunc = null, proxy = '') {
if (storageFunc && 'function' !== typeof storageFunc) {
throw new TypeError('ara-filesystem.storage: Expecting storageFunc to be a function.')
} else if (!proxy && !writable && !hasStaged(identity)) {
throw new Error('Expecting either proxy or staged files')
}
return (filename, drive, path) => {
filename = unixify(filename)
if (_isProxyFile(path, filename)) {
return _create({
path,
filename,
identity,
writable,
proxy
})
}
const file = resolve(path, filename)
return storageFunc ? storageFunc(file) : raf(file)
}
}
function _isProxyFile(path, filename) {
return 'home' === basename(path) && (filename.includes(mTreeName) || filename.includes(mSigName))
}
function _create({
filename,
identity,
writable,
proxy
} = {}) {
const fileIndex = resolveBufferIndex(filename)
if (writable) return ras({ read, write: writeStaged })
return ras({ read, write: writeNull })
async function read(req) {
const { offset, size } = req
debug(filename, 'read at offset', offset, 'size', size)
let buffer
if (hasStaged(identity)) {
buffer = readFromStaged({
did: identity,
fileIndex,
offset
})
}
if (!buffer && proxy) {
buffer = await storage.read({
address: proxy,
fileIndex,
offset
})
}
if (buffer) {
req.callback(null, _decode(buffer))
} else {
req.callback(new Error('Could not read'))
}
}
function writeStaged(req) {
const { data, offset, size } = req
debug(filename, 'staged write at offset', offset, 'size', size)
writeToStaged({
did: identity,
fileIndex,
data,
offset
})
req.callback(null)
}
function writeNull(req) {
req.callback(null)
}
}
function _decode(bytes) {
if ('string' === typeof bytes) {
bytes = bytes.replace(/^0x/, '')
bytes = Buffer.from(bytes, 'hex')
}
return Buffer.from(bytes, 'hex')
}
function resolveBufferIndex(path) {
if (!path || 'string' !== typeof path) {
throw new TypeError('Path must be non-empty string.')
}
path = unixify(path)
if (-1 === path.indexOf('/')) {
throw new Error('Path is not properly formatted.')
}
let index = -1
if (mTreeName === path) {
index = METADATA_TREE_INDEX
} else if (mSigName === path) {
index = METADATA_SIGNATURES_INDEX
}
return index
}
module.exports = {
resolveBufferIndex,
defaultStorage
}