forked from foolip/mdn-bcd-collector
-
Notifications
You must be signed in to change notification settings - Fork 0
/
storage.js
118 lines (103 loc) · 3.14 KB
/
storage.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
//
// mdn-bcd-collector: storage.js
// Module to handle temporary storage for the web app, locally or in GAE
//
// © Google LLC, Gooborg Studios
// See LICENSE.txt for copyright details
//
import assert from 'node:assert/strict';
import fs from 'fs-extra';
import {Storage} from '@google-cloud/storage';
class CloudStorage {
constructor(projectId, bucketName, appVersion) {
const storage = new Storage({projectId});
this._bucket = storage.bucket(bucketName);
// appVersion is used as a prefix for all paths, so that multiple
// deployments can use the same bucket without risk of collision.
this._version = appVersion;
}
async put(sessionId, key, value) {
assert(sessionId.length > 0);
const name = `${this._version}/sessions/${sessionId}/${encodeURIComponent(
key
)}`;
const file = this._bucket.file(name);
const data = JSON.stringify(value);
await file.save(data);
}
async getAll(sessionId) {
assert(sessionId.length > 0);
const prefix = `${this._version}/sessions/${sessionId}/`;
const files = (await this._bucket.getFiles({prefix}))[0];
const result = {};
await Promise.all(
files.map(async (file) => {
assert(file.name.startsWith(prefix));
const key = decodeURIComponent(file.name.substr(prefix.length));
const data = (await file.download())[0];
result[key] = JSON.parse(data);
})
);
return result;
}
async saveFile(filename, data) {
assert(!filename.includes('..'));
const name = `${this._version}/files/${filename}`;
const file = this._bucket.file(name);
await file.save(data);
}
async readFile(filename) {
assert(!filename.includes('..'));
const name = `${this._version}/files/${filename}`;
const file = this._bucket.file(name);
return (await file.download())[0];
}
}
class MemoryStorage {
constructor() {
this._data = new Map();
}
async put(sessionId, key, value) {
let sessionData = this._data.get(sessionId);
if (!sessionData) {
sessionData = new Map();
this._data.set(sessionId, sessionData);
}
sessionData.set(key, value);
}
async getAll(sessionId) {
const result = {};
const sessionData = this._data.get(sessionId);
if (sessionData) {
for (const [key, value] of sessionData) {
result[key] = value;
}
}
return result;
}
async saveFile(filename, data) {
assert(!filename.includes('..'));
await fs.writeFile(
new URL(`./download/${filename}`, import.meta.url),
data
);
}
async readFile(filename) {
assert(!filename.includes('..'));
return await fs.readFile(
new URL(`./download/${filename}`, import.meta.url)
);
}
}
const getStorage = (appVersion) => {
// Use CloudStorage on Google AppEngine.
const project = process.env.GOOGLE_CLOUD_PROJECT;
if (project) {
// Use GCLOUD_STORAGE_BUCKET from app.yaml.
const bucketName = process.env.GCLOUD_STORAGE_BUCKET;
return new CloudStorage(project, bucketName, appVersion);
}
// Use MemoryStorage storage for local deployment and testing.
return new MemoryStorage();
};
export {CloudStorage, MemoryStorage, getStorage};