-
Notifications
You must be signed in to change notification settings - Fork 0
/
file.ts
127 lines (96 loc) · 3.86 KB
/
file.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
import { readableStreamFromReader } from 'https://deno.land/std/streams/mod.ts';
import { Status, STATUS_TEXT, } from 'https://deno.land/std/http/http_status.ts';
import { extname, join } from 'https://deno.land/std/path/mod.ts';
import Context from './context.ts';
import Plugin from './plugin.ts';
import Mime from './mime.ts';
interface Options {
spa?: boolean;
path?: string;
}
export default class File implements Plugin {
#spa?: boolean;
#path?: string;
constructor (options?: Options) {
this.#spa = options?.spa;
this.#path = options?.path;
}
spa (data: boolean) {
this.#spa = data;
}
path (data: string) {
this.#path = data;
}
async direct (context: Context, path: string): Promise<Response> {
if (!this.#path) throw new Error('File - path required');
path = join(this.#path, decodeURIComponent(path));
let extension = extname(path).slice(1);
if (!extension) {
extension = 'html';
path = `${path}.html`;
}
let file;
try {
file = await Deno.open(path, { read: true });
} catch (error) {
if (error.name === 'NotFound') {
return context.response(Status.NotFound, STATUS_TEXT.get(Status.NotFound), STATUS_TEXT.get(Status.NotFound));
} else {
throw error;
}
}
if (!context.headers.has('content-type')) {
const mime = Mime[ extension as keyof typeof Mime ] ?? Mime[ 'default' ];
context.headers.set('content-type', `${mime};charset=utf8`);
}
const readableStream = readableStreamFromReader(file);
return context.response(Status.OK, STATUS_TEXT.get(Status.OK), readableStream);
}
async handle (context: Context): Promise<Response> {
if (!this.#path) throw new Error('File - path required');
const { url } = context;
let path = join(this.#path, decodeURIComponent(url.pathname));
let extension = extname(path).slice(1);
if (!extension) {
extension = 'html';
path = `${path}.html`;
}
let file;
try {
file = await Deno.open(path, { read: true });
} catch (error) {
if (error.name === 'NotFound') {
try {
path = join(path.slice(0, -5), 'index.html');
file = await Deno.open(path, { read: true });
} catch (error) {
if (error.name === 'NotFound') {
if (this.#spa) {
try {
file = await Deno.open(join(this.#path, 'index.html'), { read: true });
} catch (error) {
if (error.name === 'NotFound') {
return context.response(Status.NotFound, STATUS_TEXT.get(Status.NotFound), STATUS_TEXT.get(Status.NotFound));
} else {
throw error;
}
}
} else {
return context.response(Status.NotFound, STATUS_TEXT.get(Status.NotFound), STATUS_TEXT.get(Status.NotFound));
}
} else {
throw error;
}
}
} else {
throw error;
}
}
if (!context.headers.has('content-type')) {
const mime = Mime[ extension as keyof typeof Mime ] ?? Mime[ 'default' ];
context.headers.set('content-type', `${mime};charset=utf8`);
}
const readableStream = readableStreamFromReader(file);
return context.response(Status.OK, STATUS_TEXT.get(Status.OK), readableStream);
}
}