forked from restspace/rs-runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mimeHandlers.ts
106 lines (98 loc) · 4.49 KB
/
mimeHandlers.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
import { Message } from "rs-core/Message.ts";
import { Url } from "rs-core/Url.ts";
import { DirDescriptor } from "../rs-core/DirDescriptor.ts";
import { last, slashTrimLeft } from "../rs-core/utility/utility.ts";
const generatePaths = async function* (msg: Message, requestInternal?: (req: Message) => Promise<Message>): AsyncGenerator<[ Message, DirDescriptor ]> {
let dir = (await msg.data!.asJson() as DirDescriptor | DirDescriptor[]) || [];
if (Array.isArray(dir)) dir = dir[0];
yield [ msg, { ...dir } ];
if (requestInternal) {
const subdirs = dir.paths.filter(([ p ]) => p.endsWith('/'));
for (const [ subdir ] of subdirs) {
const newUrl = msg.url.follow(subdir);
newUrl.query['$list'] = [ "recursive,details,all" ];
const msgOut = await requestInternal(msg.copy().setUrl(newUrl).setData(null, ''));
const dirList = ((await msgOut.data!.asJson()) || []) as DirDescriptor[];
for (const resDir of dirList) {
resDir.paths = resDir.paths.map(([ p, ...rest ]) => [ subdir + p, ...rest ]);
yield [ msgOut, { ...resDir } ];
}
}
}
}
const dirToItems = async (msg: Message, dir: DirDescriptor, requestInternal: (req: Message) => Promise<Message>) => {
const fetchAllMessages = dir.paths
.filter(([ path ]) => !path.endsWith('/'))
.map(([ path ]) => msg.copy().setUrl(msg.url.follow(last(path.split('/')))));
const fullList: Record<string, unknown> = {};
await Promise.all(fetchAllMessages
.map(msg => requestInternal(msg)
.then(msg => msg.data!.asJson().then(data => fullList[slashTrimLeft(dir.path) + msg.url.resourceName] = data))
));
return fullList;
}
const final = (s: string) => {
const words = s.split('/');
return last(words) === '' ? words.slice(-2)[0] + '/' : last(words);
};
export const mimeHandlers: { [ mimeType: string ]: (msg: Message, url: Url, requestInternal: (req: Message) => Promise<Message>) => Promise<Message> } = {
"inode/directory+json": async (msg, url, requestInternal) => {
const listFlags = (url.query['$list'] || []).join(',') as string;
const isRecursive = listFlags.includes('recursive');
const getItems = listFlags.includes('items');
const details = listFlags.includes('details');
const pathsOnly = !(details || getItems);
const allFiles = listFlags.includes('all');
const fileInfo = listFlags.includes('fileinfo') && pathsOnly;
const noDirs = listFlags.includes('nodirs');
let results = [] as any[];
for await (const [ resMsg, resDir ] of generatePaths(msg, isRecursive ? requestInternal : undefined)) {
if (!resDir) continue;
if (!allFiles) {
resDir.paths = resDir.paths.filter(([ p ]) => !final(p).startsWith('.'));
}
if (noDirs) {
resDir.paths = resDir.paths.filter(([ p ]) => !p.endsWith('/'));
}
let result = resDir as any;
// transform resDir to get appropriate list items
if (getItems) {
result = await dirToItems(resMsg, resDir, requestInternal);
results.push(result);
} else if (pathsOnly) {
results = results.concat(resDir.paths);
} else {
results.push(result);
}
}
// transform output list
if (isRecursive) {
if (getItems) {
results = Object.assign(results[0], ...results.slice(1));
} else if (!fileInfo) {
// list of lists
results = results.flatMap(i => i);
}
if (details) {
results.forEach((r: DirDescriptor) => r.paths = r.paths.map(([ p, ...rest ]) => [
final(p),
...rest
]));
}
} else {
if (!pathsOnly) {
results = results[0];
} else if (!fileInfo) {
results = results.map(([ p ]) => p);
}
}
if (getItems) {
// list of objects
let obj = results as unknown as Record<string, unknown>;
const urlRemoveChars = (url.servicePath === '/' ? 0 : url.servicePath.length);
obj = Object.fromEntries(Object.entries(obj).map(([k, v]) => [ k.substr(urlRemoveChars), v ]));
return msg.setDirectoryJson(obj);
}
return msg.setDirectoryJson(results);
}
}