-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
121 lines (103 loc) · 3.01 KB
/
index.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
const { Router } = require('tiny-request-router')
const createError = require('http-errors')
const Papa = require('papaparse')
const camelCase = require('lodash.camelcase')
const apiKeys = new Set(API_KEYS.split(','))
const allowedIPs = new Set(ALLOWED_IPS.split(','))
function parseCSV(csvString, config) {
return new Promise((resolve, reject) => {
Papa.parse(csvString, {
...config,
complete: ({ data }) => resolve(data),
error: reject,
})
})
}
async function fetchStreams({ dateFilter } = {}) {
let dataURL
if (dateFilter) {
if (!dateFilter.match(/^\d\d\d\d-\d\d?-\d\d?$/)) {
throw createError(400, 'invalid date')
}
const query = `SELECT * WHERE dateDiff(L, date "${dateFilter}") = 0`
dataURL = `https://docs.google.com/spreadsheets/d/${DOC_ID}/gviz/tq?tqx=out:csv&headers=1&sheet=${encodeURIComponent(
ALL_SHEET_NAME,
)}&tq=${encodeURIComponent(query)}`
} else {
dataURL = `https://docs.google.com/spreadsheets/d/${DOC_ID}/gviz/tq?tqx=out:csv&headers=1&sheet=${encodeURIComponent(
CURRENT_SHEET_NAME,
)}`
}
const resp = await fetch(dataURL, {
cf: {
cacheTtl: Number(TTL), // seconds
},
})
if (!resp.ok) {
throw createError(500, 'failed to fetch data from backend')
}
const csv = await resp.text()
const rows = await parseCSV(csv, {
header: true,
transformHeader: camelCase,
})
return rows
}
const baseHeaders = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
}
const cacheHeaders = {
'Cache-Control': `max-age=${TTL}`,
}
const router = new Router()
router.get('/streams.json', async (requestURL, event) => {
const key = requestURL.searchParams.get('key')
const reqIP = event.request.headers.get('cf-connecting-ip')
let responseData = []
if (apiKeys.has(key) || allowedIPs.has(reqIP)) {
const dateFilter = requestURL.searchParams.get('date')
const streams = await fetchStreams({ dateFilter })
responseData = streams.filter(({ link, platform }) => link && platform)
}
return new Response(JSON.stringify(responseData), {
headers: {
...baseHeaders,
...cacheHeaders,
},
})
})
router.get('/stats.json', async () => {
const streams = await fetchStreams()
const responseData = {
tracking: streams.length,
live: streams.filter(({ status }) => status === 'Live').length,
}
return new Response(JSON.stringify(responseData), {
headers: {
...baseHeaders,
...cacheHeaders,
},
})
})
addEventListener('fetch', async (event) => {
const { request } = event
const requestURL = new URL(request.url)
const match = router.match(request.method, requestURL.pathname)
let response
try {
if (match) {
event.respondWith(match.handler(requestURL, event))
} else {
throw createError(404)
}
} catch (err) {
if (createError.isHttpError(err)) {
return new Response(JSON.stringify({ error: err.message }), {
status: err.status,
headers: baseHeaders,
})
}
throw err
}
})