Skip to content
This repository was archived by the owner on Nov 21, 2020. It is now read-only.

Commit 1948f45

Browse files
munkhorgilBattulga BatAmar
authored andcommitted
Google cloud storage util (#395)
Close #404
1 parent 6380c12 commit 1948f45

File tree

7 files changed

+172
-13
lines changed

7 files changed

+172
-13
lines changed

.env.sample

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,16 @@ GOOGLE_SUBSCRIPTION_NAME=''
5858
GOOGLE_PROJECT_ID=''
5959
GMAIL_REDIRECT_URL = http://localhost:3300/
6060

61+
# Google Cloud Storage
62+
GOOGLE_CLOUD_STORAGE_BUCKET=''
63+
6164
ERXES_PATH=''
6265
API_PATH=''
6366
WIDGET_PATH=''
6467
WIDGET_API_PATH=''
68+
69+
# AWS | GCS
70+
UPLOAD_SERVICE_TYPE='AWS'
71+
72+
# File system: true | ''
73+
FILE_SYSTEM_PUBLIC='true'

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ dump.rdb
1212
*.swo
1313
.migrate
1414

15-
# Firebase config key
16-
serviceAccount.json
15+
# Google config file
16+
google_cred.json

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
},
4747
"dependencies": {
4848
"@google-cloud/pubsub": "0.18.0",
49+
"@google-cloud/storage": "^2.5.0",
4950
"apollo-server-express": "^2.3.1",
5051
"aws-sdk": "^2.151.0",
5152
"bcrypt": "^3.0.2",

src/data/utils.ts

Lines changed: 137 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Storage } from '@google-cloud/storage';
12
import * as AWS from 'aws-sdk';
23
import * as EmailValidator from 'email-deep-validator';
34
import * as fileType from 'file-type';
@@ -50,20 +51,54 @@ export const checkFile = async file => {
5051
return 'ok';
5152
};
5253

53-
/*
54-
* Save binary data to amazon s3
54+
/**
55+
* Create AWS instance
5556
*/
56-
export const uploadFile = async (file: { name: string; path: string }): Promise<string> => {
57+
const createAWS = () => {
5758
const AWS_ACCESS_KEY_ID = getEnv({ name: 'AWS_ACCESS_KEY_ID' });
5859
const AWS_SECRET_ACCESS_KEY = getEnv({ name: 'AWS_SECRET_ACCESS_KEY' });
5960
const AWS_BUCKET = getEnv({ name: 'AWS_BUCKET' });
60-
const AWS_PREFIX = getEnv({ name: 'AWS_PREFIX', defaultValue: '' });
61+
62+
if (!AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY || !AWS_BUCKET) {
63+
throw new Error('AWS credentials are not configured');
64+
}
6165

6266
// initialize s3
63-
const s3 = new AWS.S3({
67+
return new AWS.S3({
6468
accessKeyId: AWS_ACCESS_KEY_ID,
6569
secretAccessKey: AWS_SECRET_ACCESS_KEY,
6670
});
71+
};
72+
73+
/**
74+
* Create Google Cloud Storage instance
75+
*/
76+
const createGCS = () => {
77+
const GOOGLE_APPLICATION_CREDENTIALS = getEnv({ name: 'GOOGLE_APPLICATION_CREDENTIALS' });
78+
const GOOGLE_PROJECT_ID = getEnv({ name: 'GOOGLE_PROJECT_ID' });
79+
const BUCKET = getEnv({ name: 'GOOGLE_CLOUD_STORAGE_BUCKET' });
80+
81+
if (!GOOGLE_PROJECT_ID || !GOOGLE_APPLICATION_CREDENTIALS || !BUCKET) {
82+
throw new Error('Google Cloud Storage credentials are not configured');
83+
}
84+
85+
// initializing Google Cloud Storage
86+
return new Storage({
87+
projectId: GOOGLE_PROJECT_ID,
88+
keyFilename: GOOGLE_APPLICATION_CREDENTIALS,
89+
});
90+
};
91+
92+
/*
93+
* Save binary data to amazon s3
94+
*/
95+
export const uploadFileAWS = async (file: { name: string; path: string }): Promise<string> => {
96+
const AWS_BUCKET = getEnv({ name: 'AWS_BUCKET' });
97+
const AWS_PREFIX = getEnv({ name: 'AWS_PREFIX', defaultValue: '' });
98+
const IS_PUBLIC = getEnv({ name: 'FILE_SYSTEM_PUBLIC', defaultValue: 'true' });
99+
100+
// initialize s3
101+
const s3 = createAWS();
67102

68103
// generate unique name
69104
const fileName = `${AWS_PREFIX}${Math.random()}${file.name}`;
@@ -78,7 +113,7 @@ export const uploadFile = async (file: { name: string; path: string }): Promise<
78113
Bucket: AWS_BUCKET,
79114
Key: fileName,
80115
Body: buffer,
81-
ACL: 'public-read',
116+
ACL: IS_PUBLIC === 'true' ? 'public-read' : undefined,
82117
},
83118
(err, res) => {
84119
if (err) {
@@ -90,7 +125,102 @@ export const uploadFile = async (file: { name: string; path: string }): Promise<
90125
);
91126
});
92127

93-
return response.Location;
128+
return IS_PUBLIC === 'true' ? response.Location : fileName;
129+
};
130+
131+
/*
132+
* Save file to google cloud storage
133+
*/
134+
export const uploadFileGCS = async (file: { name: string; path: string; type: string }): Promise<string> => {
135+
const BUCKET = getEnv({ name: 'GOOGLE_CLOUD_STORAGE_BUCKET' });
136+
const IS_PUBLIC = getEnv({ name: 'FILE_SYSTEM_PUBLIC', defaultValue: 'true' });
137+
138+
// initialize GCS
139+
const storage = createGCS();
140+
141+
// select bucket
142+
const bucket = storage.bucket(BUCKET);
143+
144+
// generate unique name
145+
const fileName = `${Math.random()}${file.name}`;
146+
147+
bucket.file(fileName);
148+
149+
const response: any = await new Promise((resolve, reject) => {
150+
bucket.upload(
151+
file.path,
152+
{
153+
metadata: { contentType: file.type },
154+
public: IS_PUBLIC === 'true',
155+
},
156+
(err, res) => {
157+
if (err) {
158+
return reject(err);
159+
}
160+
161+
if (res) {
162+
return resolve(res);
163+
}
164+
},
165+
);
166+
});
167+
168+
const { metadata, name } = response;
169+
170+
return IS_PUBLIC === 'true' ? metadata.mediaLink : name;
171+
};
172+
173+
/**
174+
* Read file from GCS, AWS
175+
*/
176+
export const readFileRequest = async (key: string): Promise<any> => {
177+
const UPLOAD_SERVICE_TYPE = getEnv({ name: 'UPLOAD_SERVICE_TYPE', defaultValue: 'AWS' });
178+
179+
if (UPLOAD_SERVICE_TYPE === 'GCS') {
180+
const GCS_BUCKET = getEnv({ name: 'GOOGLE_CLOUD_STORAGE_BUCKET' });
181+
const storage = createGCS();
182+
183+
const bucket = storage.bucket(GCS_BUCKET);
184+
185+
const file = bucket.file(key);
186+
187+
// get a file buffer
188+
const [contents] = await file.download({});
189+
190+
return contents;
191+
}
192+
193+
const AWS_BUCKET = getEnv({ name: 'AWS_BUCKET' });
194+
const s3 = createAWS();
195+
196+
return new Promise((resolve, reject) => {
197+
s3.getObject(
198+
{
199+
Bucket: AWS_BUCKET,
200+
Key: key,
201+
},
202+
(error, response) => {
203+
if (error) {
204+
return reject(error);
205+
}
206+
207+
return resolve(response.Body);
208+
},
209+
);
210+
});
211+
};
212+
213+
/*
214+
* Save binary data to amazon s3
215+
*/
216+
export const uploadFile = async (file): Promise<string> => {
217+
const UPLOAD_SERVICE_TYPE = getEnv({ name: 'UPLOAD_SERVICE_TYPE', defaultValue: 'AWS' });
218+
219+
if (UPLOAD_SERVICE_TYPE === 'AWS') {
220+
return uploadFileAWS(file);
221+
}
222+
223+
return uploadFileGCS(file);
94224
};
95225

96226
/**

src/index.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { userMiddleware } from './auth';
1212
import resolvers from './data/resolvers';
1313
import { handleEngageUnSubscribe } from './data/resolvers/mutations/engageUtils';
1414
import typeDefs from './data/schema';
15-
import { checkFile, getEnv, importXlsFile, uploadFile } from './data/utils';
15+
import { checkFile, getEnv, importXlsFile, readFileRequest, uploadFile } from './data/utils';
1616
import { connect } from './db/connection';
1717
import { Conversations, Customers } from './db/models';
1818
import { graphqlPubsub } from './pubsub';
@@ -27,13 +27,13 @@ const MAIN_APP_DOMAIN = getEnv({ name: 'MAIN_APP_DOMAIN', defaultValue: '' });
2727
const WIDGETS_DOMAIN = getEnv({ name: 'WIDGETS_DOMAIN', defaultValue: '' });
2828

2929
// firebase app initialization
30-
fs.exists(path.join(__dirname, '..', '/serviceAccount.json'), exists => {
30+
fs.exists(path.join(__dirname, '..', '/google_cred.json'), exists => {
3131
if (!exists) {
3232
return;
3333
}
3434

3535
const admin = require('firebase-admin').default;
36-
const serviceAccount = require('../serviceAccount.json');
36+
const serviceAccount = require('../google_cred.json');
3737
const firebaseServiceAccount = serviceAccount;
3838

3939
if (firebaseServiceAccount.private_key) {
@@ -196,6 +196,25 @@ app.get('/status', async (_req, res) => {
196196
res.end('ok');
197197
});
198198

199+
// read file
200+
app.get('/read-file', async (req: any, res) => {
201+
const key = req.query.key;
202+
203+
if (!key) {
204+
return res.send('Invalid key');
205+
}
206+
207+
try {
208+
const response = await readFileRequest(key);
209+
210+
res.attachment(key);
211+
212+
return res.send(response);
213+
} catch (e) {
214+
return res.end(e.message);
215+
}
216+
});
217+
199218
// file upload
200219
app.post('/upload-file', async (req, res) => {
201220
const form = new formidable.IncomingForm();

yarn.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@
151151
through2 "^2.0.3"
152152
uuid "^3.1.0"
153153

154-
"@google-cloud/storage@^2.3.0":
154+
"@google-cloud/storage@^2.3.0", "@google-cloud/storage@^2.5.0":
155155
version "2.5.0"
156156
resolved "https://registry.yarnpkg.com/@google-cloud/storage/-/storage-2.5.0.tgz#9dd3566d8155cf5ba0c212208f69f9ecd47fbd7e"
157157
dependencies:

0 commit comments

Comments
 (0)