-
Notifications
You must be signed in to change notification settings - Fork 3
/
302.js
148 lines (130 loc) · 4.43 KB
/
302.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
142
143
144
145
146
147
addEventListener("fetch", event => {
event.respondWith(handler(event.request));
});
const query = `
repo = from(bucket:"mirrorz")
|> range(start: -10m)
|> filter(fn: (r) => r._measurement == "repo" and r.name == "reponame")
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
|> filter(fn: (r) => r.disable != true)
|> map(fn: (r) => ({_value:r.value,mirror:r.mirror,_time:r._time,path:r.url}))
|> tail(n:1)
site = from(bucket:"mirrorz")
|> range(start: -10m)
|> filter(fn: (r) => r._measurement == "site")
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
|> filter(fn: (r) => r.disable != true)
|> map(fn: (r) => ({mirror:r.mirror,url:r.url}))
|> tail(n:1)
join(tables: {repo: repo, site: site}, on: ["mirror"])
|> map(fn: (r) => ({_value:r._value,mirror:r.mirror,url:r.url+r.path,_time:r._time}))
`
function is_debug(request) {
const params = {};
const req_url = new URL(request.url);
const queryString = req_url.search.slice(1).split('&');
queryString.forEach(item => {
const kv = item.split('=')
if (kv[0]) {
if (kv[0] in params) {
params[kv[0]].push(kv[1] || true)
} else {
params[kv[0]] = [kv[1] || true]
}
}
});
return ('trace' in params);
}
function newest(parsed) {
let m = -Infinity;
let url = null;
for (const mirror of parsed) {
try {
const v = parseInt(mirror.value);
// 0 is a special value, namely unknown!
// valid range: v < 0
if (v == 0)
continue;
if (v > m) {
m = v;
url = mirror.url;
}
} catch (e) {}
}
return url;
}
function decide(parsed) {
return newest(parsed);
}
function parse_csv(csv) {
let index_value, index_mirror, index_url;
let result = [];
for (const line of csv.split('\r\n')) {
const arr = line.split(',');
if (arr.length < 7)
continue
if (arr[1] === "result") {
for (let i = 3; i != 7; ++i) {
switch(arr[i]) {
case "_value":
index_value = i;
break;
case "mirror":
index_mirror = i;
break;
case "url":
index_url = i;
break;
}
}
} else if (arr[1] === "_result") {
result.push({
"value": arr[index_value],
"url": arr[index_url],
"mirror": arr[index_mirror],
});
}
}
return result;
}
async function handler(request) {
try {
let pathname = (new URL(request.url)).pathname;
let pathname_arr = pathname.split('/');
// Redirect to homepage
if (pathname_arr[1].length === 0)
return Response.redirect('https://mirrorz.org/about', 302);
// Query influxdb 2.x
const influx_url = new URL("/api/v2/query", INFLUX_URL).toString();
const response = await fetch(influx_url, {
headers: {
'Authorization': 'Token ' + INFLUX_TOKEN,
'Accept': 'application/csv',
'Content-Type': 'application/vnd.flux',
},
method: "POST",
body: query.replace('reponame', pathname_arr[1]),
});
const status = await response.status;
const csv = await response.text();
// console.log(csv);
if (status >= 400) {
return new Response(`get HTTP ${status} from influxdb`, {status: status});
}
const parsed = parse_csv(csv);
if (is_debug(request))
return new Response(JSON.stringify(parsed, null, 2));
const url = decide(parsed);
if (url === null)
return new Response(`Not Found`, {status: 404});
// Append the remaining path
let remain_path = pathname.substr(1+pathname_arr[1].length);
// Dark magic for some sites treating '/archlinux' as file, not directory
if (remain_path.length === 0 && !pathname.endsWith('/'))
remain_path = '/'
const redir_url = url + remain_path;
return Response.redirect(redir_url, 302);
} catch (err) {
return new Response(`${err}`, { status: 500 })
}
}