Skip to content

Commit a64b43e

Browse files
committed
more speaker list bits
1 parent 6ec2ccc commit a64b43e

37 files changed

+577
-90
lines changed

.arc-env-example

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# .arc-env
22
@testing
33
BEGIN_STATIC_ORIGIN /_static
4-
CARTER_RULES foo
4+
ADMIN_PASSWORD foo
55
TITO_WEBHOOK_KEY abcd1234
66
SLACK_JOIN_URL https://join.slack.com/t/cascadiajs/shared_invite/foo

app.arc

+6-3
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ fingerprint true
99
src src/views
1010

1111
@http
12-
get /changelog
13-
get /admin
12+
get /admin
13+
get /changelog
14+
get /modules/:type/:module
15+
get /speakers
16+
get /speakers/:key
1417
post /login
15-
post /upload
18+
post /speakers
1619
get /*
1720

1821
@tables

package-lock.json

+57-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
},
2121
"dependencies": {
2222
"@architect/functions": "^3.14.1",
23+
"esm": "^3.2.25",
2324
"front-matter": "^4.0.2",
24-
"marked": "^2.0.6"
25+
"marked": "^2.0.6",
26+
"rollup": "^2.56.2"
2527
}
2628
}

scripts/upload-speakers.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ async function uploadSpeakers(env, password) {
2525
let cookie = login.headers.get('set-cookie')
2626

2727
// upload the speakers
28-
let speakers = await fetch(`${url}/upload`, {
28+
let speakers = await fetch(`${url}/speakers`, {
2929
method: 'POST',
3030
headers: {cookie, 'Content-Type': 'application/json'},
3131
body: JSON.stringify(speakerData),

src/http/get-admin/index.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,20 @@ exports.handler = arc.http.async(unauthenticated, authenticated)
1313
async function unauthenticated(req) {
1414
if (req.session.loggedIn) return
1515
else {
16-
let form = `<form action=/login method=post>
17-
<input type=password name=password>
18-
</form>`
16+
let form = `
17+
<h1>Please log-in</h1>
18+
<form action=/login method=post>
19+
<input type=password name=password>
20+
<input type=submit value=Log-In>
21+
</form>`
1922
let html = layout(form)
2023
return { html }
2124
}
2225
}
2326

2427
/** render the speaker list/form */
2528
async function authenticated(req) {
26-
let speakerData = await data.get({ table: 'speakers', limit: 24 })
29+
let speakerData = await data.get({ table: 'speakers', limit: 20 })
2730
if (req.query.export === 'speakers') {
2831
return { json: speakerData }
2932
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const { rollup } = require('rollup')
2+
const path = require('../cache/cache-path')
3+
const write = require('../cache/cache-write')
4+
5+
module.exports = async function bundle({ type, mod }) {
6+
console.time('bundle')
7+
let key = `${type}/${mod}`
8+
let input = path(key)
9+
let bundle = await rollup({ input })
10+
let bundled = await bundle.generate({ format: 'esm' })
11+
let body = bundled.output[0].code
12+
console.timeEnd('bundle')
13+
14+
return write({ key, body, type })
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const { join } = require('path')
2+
3+
module.exports = function cachePath (filename) {
4+
return join(process.cwd(), 'node_modules', '@architect', 'views', 'modules', filename)
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const { existsSync } = require('fs')
2+
const data = require('@begin/data')
3+
const path = require('./cache-path')
4+
5+
module.exports = async function read({ type, mod }) {
6+
let key = `${type}/${mod}`
7+
8+
// Get the cache contents
9+
let cache = await data.get({ table: 'module-cache' })
10+
11+
// Fingerprinted requests
12+
let file = cache.length && cache.find(f => mod === f.filename && type === f.type) || false
13+
14+
// Non-fingerprinted requests
15+
let forward = cache.find(f => key === f.key)
16+
let upgrade = false
17+
if (forward && forward.filename) {
18+
// If the build changed (or working locally) kick off a bundle
19+
let build = process.env.BEGIN_BUILD_COMMIT_SHA
20+
if (!build || (forward.build !== build)) return {}
21+
upgrade = forward.filename
22+
}
23+
24+
// Look for the entry file on the filesystem to ensure validity
25+
if (!file && !existsSync(path(key)))
26+
throw ReferenceError(`not_found: ${ key }`)
27+
28+
return { file, upgrade }
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const data = require('@begin/data')
2+
const crypto = require('crypto')
3+
4+
module.exports = async function write ({ key, body, type }) {
5+
6+
// Fingerprint it
7+
console.time('fingerprint')
8+
let hash = crypto.createHash('sha1')
9+
hash.update(Buffer.from(body))
10+
let sha = hash.digest('hex').substr(0, 7)
11+
let [file, extension] = key.split('/').slice(0).reverse().shift().split('.')
12+
let filename = `${ file }-${ sha }.${ extension }`
13+
console.timeEnd('fingerprint')
14+
15+
// Cache it
16+
console.time('begin-data-cache')
17+
let bundle = {
18+
table: 'module-cache',
19+
key,
20+
type,
21+
filename,
22+
body,
23+
headers: {
24+
'content-type': `text/${ extension === 'js' ? 'javascript' : 'css' }; charset=UTF-8`,
25+
'cache-control': 'max-age=315360000'
26+
},
27+
}
28+
let build = process.env.BEGIN_BUILD_COMMIT_SHA
29+
if (build) bundle.build = build
30+
await data.set(bundle)
31+
console.timeEnd('begin-data-cache')
32+
33+
return filename
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
const read = require('./cache/cache-read')
2+
const bundle = require('./bundle')
3+
const waterfall = require('./responses/200')
4+
const redirect = require('./responses/302')
5+
const notfound = require('./responses/404')
6+
const fatal = require('./responses/500')
7+
8+
/**
9+
* Progressive bundling endpoint
10+
* - Receives a plain entry file request ......... `/modules/entry/speakers.js`
11+
* - And upgrades it to a fingerprinted bundle ... `/modules/entry/speakers-ea4b26c.js`
12+
*/
13+
exports.handler = async function http (req) {
14+
let { type, module: mod } = req.pathParameters
15+
let debug = process.env.DEBUG
16+
17+
try {
18+
if (debug) {
19+
return waterfall(req)
20+
}
21+
else {
22+
// Check to see if file is already in the bundle cache
23+
let { file, upgrade } = await read({ type, mod })
24+
25+
// If we found the file, deliver it
26+
if (file) {
27+
let { body, headers } = file
28+
return {
29+
statusCode: 200,
30+
body,
31+
headers
32+
}
33+
}
34+
35+
// If this is a valid request against a cache hit, upgrade to the bundle
36+
if (upgrade) {
37+
return redirect(upgrade)
38+
}
39+
40+
// Otherwise, bundle it
41+
else {
42+
let fingerprinted = await bundle({ type, mod })
43+
return redirect(fingerprinted)
44+
}
45+
}
46+
}
47+
catch(err) {
48+
if (err.message.includes('not_found')) {
49+
return notfound(`${type}/${mod}`)
50+
}
51+
return fatal(err)
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const { promisify } = require('util')
2+
const fs = require('fs')
3+
const readFile = promisify(fs.readFile)
4+
const join = require('path').join
5+
6+
module.exports = async function ok (req) {
7+
let { type, module: mod } = req.pathParameters
8+
let requested = join(process.cwd(), 'node_modules', '@architect', 'views', 'modules', type, mod)
9+
let js = await readFile(requested)
10+
11+
return {
12+
statusCode: 200,
13+
headers: {
14+
'content-type': 'text/javascript; charset=utf8'
15+
},
16+
body: js.toString()
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module.exports = function redirect (location) {
2+
return {
3+
statusCode: 302,
4+
headers: {
5+
location,
6+
'cache-control': 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0'
7+
}
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module.exports = function notfound (file) {
2+
return {
3+
statusCode: 404,
4+
headers: {
5+
'content-type': 'text/html; charset=utf8'
6+
},
7+
body: `404 not found: /modules/${ file }`
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = function error (err) {
2+
console.error(err)
3+
return {
4+
statusCode: 500,
5+
headers: {
6+
'content-type': 'text/html; charset=utf8'
7+
},
8+
body: `500 / ssr render error: ${err.message}`
9+
}
10+
}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@aws
2+
runtime nodejs12.x
3+
# memory 1152
4+
# timeout 30
5+
# concurrency 1

src/http/get-speakers-000key/index.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
let arc = require('@architect/functions')
2+
const getSpeakerData = require('@architect/shared/data/get-speaker-data')
3+
const SpeakerView = require('@architect/views/speaker')
4+
5+
async function Speaker(req) {
6+
const { key } = req.params
7+
const { social } = req.queryStringParameters
8+
const { speakers } = getSpeakerData(req)
9+
const speaker = speakers.find(s => s.key === key)
10+
11+
return await SpeakerView({speaker, social})
12+
13+
}
14+
15+
exports.handler = arc.http.async(Speaker)

src/http/get-speakers/config.arc

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@aws
2+
runtime nodejs12.x
3+
# memory 1152
4+
# timeout 30
5+
# concurrency 1

0 commit comments

Comments
 (0)