Skip to content

Commit aae726f

Browse files
committed
TwoDotO to AWS
1 parent a02cd40 commit aae726f

23 files changed

+6653
-313
lines changed

.eslintrc.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"env": {
3+
"browser": true,
4+
"commonjs": true,
5+
"es6": true
6+
},
7+
"extends": "eslint:recommended",
8+
"parserOptions": {
9+
"ecmaFeatures": {
10+
"experimentalObjectRestSpread": true,
11+
"jsx": true
12+
},
13+
"sourceType": "module"
14+
},
15+
"plugins": [
16+
"react"
17+
],
18+
"rules": {
19+
"indent": [
20+
"error",
21+
4
22+
],
23+
"linebreak-style": [
24+
"error",
25+
"unix"
26+
],
27+
"quotes": [
28+
"error",
29+
"single"
30+
],
31+
"semi": [
32+
"error",
33+
"always"
34+
]
35+
}
36+
}

bin/deploy.js

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
const AWS = require('aws-sdk');
2+
3+
const fs = require('fs');
4+
const klaw = require('klaw');
5+
const path = require('path');
6+
const debug = require('debug')('app:bin:deploy');
7+
const crypto = require('crypto');
8+
const project = require('../config/project.config');
9+
const through2 = require('through2');
10+
const mime = require('mime-types');
11+
const argv = require('yargs').argv
12+
13+
const s3 = new AWS.S3({
14+
region: 'eu-west-1',
15+
});
16+
17+
function promisify(fn, thisScope) {
18+
return function decorator(...args) {
19+
return new Promise((resolve, reject) => {
20+
args.push((err, data) => {
21+
if (err) return reject(err);
22+
return resolve(data);
23+
});
24+
25+
fn.apply(thisScope, args);
26+
});
27+
};
28+
}
29+
30+
const readFile = promisify(fs.readFile);
31+
const s3HeadObject = promisify(s3.headObject, s3);
32+
const s3Upload = promisify(s3.upload, s3);
33+
34+
function stripPath(inputPath, absPathPrefix) {
35+
return inputPath.slice(absPathPrefix.length + 1);
36+
}
37+
38+
function uploadFile(objectKey, fileData) {
39+
debug('Uploading file', objectKey);
40+
41+
return s3Upload({
42+
Bucket: project.bucket_name,
43+
Key: objectKey,
44+
Body: fileData,
45+
ContentType: mime.contentType(objectKey),
46+
});
47+
}
48+
49+
function checkMD5AndUpload(absPathPrefix, item) {
50+
const objectKey = stripPath(item.path, absPathPrefix);
51+
52+
let fileMD5, fileData;
53+
54+
return readFile(item.path)
55+
.then(
56+
(fd) => {
57+
fileData = fd;
58+
fileMD5 = crypto.createHash('md5').update(fileData).digest('hex');
59+
60+
return s3HeadObject({
61+
Bucket: project.bucket_name,
62+
Key: objectKey,
63+
});
64+
},
65+
(err) => {
66+
debug('Unable to read file', item.path, err);
67+
}
68+
)
69+
.then(
70+
(data) => {
71+
if (! data) return;
72+
73+
const etag = JSON.parse(data['ETag']);
74+
75+
if (!argv.all && fileMD5 !== etag) {
76+
return uploadFile(objectKey, fileData);
77+
}
78+
},
79+
(err) => {
80+
if (err.code === 'NotFound')
81+
return uploadFile(objectKey, fileData);
82+
debug('ERROR S3', objectKey, err);
83+
}
84+
)
85+
.catch(
86+
(err) => {
87+
debug('Uncaught Error', err);
88+
}
89+
);
90+
}
91+
92+
const deploy = (directory, absPathPrefix) => {
93+
absPathPrefix = absPathPrefix || directory;
94+
95+
debug('Performing Deploy', directory);
96+
debug('NODE_ENV', project.env);
97+
98+
const upload = through2.obj(function(item, enc, next) {
99+
const result = checkMD5AndUpload(absPathPrefix, item);
100+
this.push(result);
101+
next();
102+
});
103+
104+
const excludeDirFilter = through2.obj(function(item, enc, next) {
105+
if (! item.stats.isDirectory()) this.push(item);
106+
next();
107+
});
108+
109+
const waitForCompletion = through2.obj(function(item, enc, next) {
110+
item.then(() => next(), () => next());
111+
});
112+
113+
return klaw(directory)
114+
.pipe(excludeDirFilter)
115+
.pipe(upload)
116+
.pipe(waitForCompletion)
117+
.on('data', () => {
118+
debug('DONE');
119+
})
120+
};
121+
122+
const dist = path.join(__dirname, '../dist');
123+
const themes = path.join(__dirname, '../node_modules/codemirror/theme');
124+
125+
deploy(dist)
126+
.on('end', () => {
127+
deploy(themes, path.join(__dirname, '../node_modules'));
128+
});

config/environments.config.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,31 @@ module.exports = {
99
// are served webpack by to fix this issue:
1010
// http://stackoverflow.com/questions/34133808/webpack-ots-parsing-error-loading-fonts/34133809#34133809
1111
development : (config) => ({
12-
compiler_public_path : `http://${config.server_host}:${config.server_port}/`
12+
compiler_public_path : `http://${config.server_host}:${config.server_port}/`,
13+
}),
14+
15+
staging: (config) => ({
16+
bucket_name : 'staging.es6console.com',
17+
api_server_host : 'https://api-staging.es6console.com/v1/',
18+
s3_server_host : 'http://staging.es6console.com/',
19+
compiler_public_path : '/',
20+
compiler_fail_on_warning : false,
21+
compiler_hash_type : 'chunkhash',
22+
compiler_devtool : 'source-map',
23+
compiler_stats : {
24+
chunks : true,
25+
chunkModules : true,
26+
colors : true
27+
}
1328
}),
1429

1530
// ======================================================
1631
// Overrides when NODE_ENV === 'production'
1732
// ======================================================
1833
production : (config) => ({
19-
api_server_host : 'https://eq0z5hd8w3.execute-api.eu-west-1.amazonaws.com/prod/',
20-
s3_server_host : 'http://es6console.s3-website-eu-west-1.amazonaws.com/',
34+
bucket_name : 'es6console.com',
35+
api_server_host : 'https://api.es6console.com/v1/',
36+
s3_server_host : 'http://es6console.com/',
2137
compiler_public_path : '/',
2238
compiler_fail_on_warning : false,
2339
compiler_hash_type : 'chunkhash',

config/project.config.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ const config = {
3333
api_server_host : 'http://localhost:3000/', // use string 'localhost' to prevent exposure on local network
3434
s3_server_host : 'http://localhost:8000/',
3535

36+
// ----------------------------------
37+
// AWS Configuration
38+
// ----------------------------------
39+
bucket_name : 'staging.es6console.com',
40+
3641
// ----------------------------------
3742
// Compiler Configuration
3843
// ----------------------------------
@@ -112,7 +117,13 @@ config.paths = {
112117
// ========================================================
113118
debug(`Looking for environment overrides for NODE_ENV "${config.env}".`)
114119
const environments = require('./environments.config')
115-
const overrides = environments[config.env]
120+
let overrides = environments[config.env]
121+
122+
if (config.env === 'dev') {
123+
debug('Found serverless environment dev which translates to staging AWS env');
124+
overrides = environments['staging'];
125+
}
126+
116127
if (overrides) {
117128
debug('Found overrides, applying to default configuration.')
118129
Object.assign(config, overrides(config))

lambda/storage/api/create.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ module.exports.handler = (event, context, callback) => {
3838

3939
const response = {
4040
statusCode: 201,
41+
headers: {
42+
'Access-Control-Allow-Origin': '*',
43+
},
4144
body: JSON.stringify({
4245
message: 'Saved snippet',
4346
saved: true,

lambda/storage/api/examples.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22
const aws = require('aws-sdk');
3+
const project = require('../config/project.config.js');
34

45
const options = {
56
region: 'eu-west-1',
@@ -40,7 +41,7 @@ module.exports.handler = (event, context, callback) => {
4041
const s3 = new aws.S3(options);
4142

4243
const params = {
43-
Bucket: 'es6console',
44+
Bucket: project.bucket_name,
4445
Delimiter: '/',
4546
Prefix: 'examples/',
4647
};
@@ -52,14 +53,17 @@ module.exports.handler = (event, context, callback) => {
5253

5354
Promise.all(prefixes.map((prefix) =>
5455
listObjects(s3, {
55-
Bucket: 'es6console',
56+
Bucket: project.bucket_name,
5657
Delimiter: '/',
5758
Prefix: prefix,
5859
})
5960
)).then((data) => {
6061
const content = makeBody(data);
6162
const response = {
6263
statusCode: 200,
64+
headers: {
65+
'Access-Control-Allow-Origin': '*',
66+
},
6367
body: JSON.stringify(content),
6468
};
6569

lambda/storage/api/get.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ module.exports.handler = (event, context, callback) => {
2020

2121
const response = {
2222
statusCode: 200,
23+
headers: {
24+
'Access-Control-Allow-Origin': '*',
25+
},
2326
body: JSON.stringify({
2427
message: 'Retrieved snippet',
2528
snippet: data.Item.code.S,

lambda/storage/api/themes.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use strict';
2+
const aws = require('aws-sdk');
3+
const project = require('../config/project.config.js');
4+
5+
const options = {
6+
region: 'eu-west-1',
7+
};
8+
9+
function trimItem(key) {
10+
const pattern = /codemirror\/theme\/([^.]*)\.css$/;
11+
return key.match(pattern)[1];
12+
}
13+
14+
function makeBody(data) {
15+
return {
16+
themes: data.Contents.map((item) => trimItem(item.Key)),
17+
};
18+
}
19+
20+
module.exports.handler = (event, context, callback) => {
21+
const s3 = new aws.S3(options);
22+
23+
const params = {
24+
Bucket: project.bucket_name,
25+
Delimiter: '/',
26+
Prefix: 'codemirror/theme/',
27+
};
28+
29+
s3.listObjects(params, (err, data) => {
30+
if (err) return callback(err);
31+
32+
const content = makeBody(data);
33+
const response = {
34+
statusCode: 200,
35+
headers: {
36+
'Access-Control-Allow-Origin': '*',
37+
},
38+
body: JSON.stringify(content),
39+
};
40+
41+
callback(null, response);
42+
});
43+
};

lambda/storage/config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/Users/matthisk/src/es6console/config

0 commit comments

Comments
 (0)