-
Notifications
You must be signed in to change notification settings - Fork 0
/
google.js
125 lines (110 loc) · 3.76 KB
/
google.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
122
123
124
125
const { google } = require("googleapis")
const request = require("request")
const HttpError = require("standard-http-error")
const { GOOGLE_FILE_PATH, CALLBACK_URL, GOOGLE_API_ENDPOINT } = require("./constants")
const { log, readJson, writeJson, prompt } = require("./utils")
module.exports = async () => {
let googleTokens
const clientId = process.env.GOOGLE_CLIENT_ID
const clientSecret = process.env.GOOGLE_CLIENT_SECRET
if (!clientId || !clientSecret) {
throw new Error("Could not read GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET from environment.")
}
const googleOauth = new google.auth.OAuth2(clientId, clientSecret, CALLBACK_URL)
googleOauth.on("tokens", (tokens) => {
if (!tokens.refresh_token && googleTokens) {
tokens.refresh_token = googleTokens.refresh_token // retrieve from before
}
writeJson(GOOGLE_FILE_PATH, tokens)
})
try {
googleTokens = readJson(GOOGLE_FILE_PATH)
} catch (error) {
const url = googleOauth.generateAuthUrl({
access_type: "offline",
scope: ["https://www.googleapis.com/auth/photoslibrary.appendonly"],
prompt: "consent", // to always get a refresh_token
})
log("Go to " + url)
const code = await prompt("Paste your code: ")
const { tokens } = await googleOauth.getToken(code)
googleOauth.setCredentials(tokens)
googleTokens = tokens
}
const refreshTokenIfNeeded = async () => {
if (googleTokens.expiry_date < Date.now() + 60000) {
// expires in less than a minute
log("Access token expired => refreshing")
const { tokens } = await googleOauth.refreshToken(googleTokens.refresh_token)
tokens.refresh_token = googleTokens.refresh_token // because it's not sent again, only the first time
googleTokens = tokens // eslint-disable-line require-atomic-updates
}
}
const stream = async (url, filename) => {
await refreshTokenIfNeeded()
return new Promise((resolve, reject) => {
request
.get(url)
// .on("response", (response) => {
// log("downloaded", response.statusCode, response.statusMessage, response.headers)
// })
.on("error", (error) => {
reject(error)
})
.pipe(
request.post(
{
url: GOOGLE_API_ENDPOINT + "uploads",
headers: {
// "Content-type": "application/octet-stream",
// "Content-length": set by stream
"X-Goog-Upload-File-Name": filename,
"X-Goog-Upload-Protocol": "raw",
Authorization: `Bearer ${googleTokens.access_token}`,
},
},
(error, response, body) => {
if (error) {
reject(error)
} else {
resolve(body)
}
}
)
)
})
}
const post = async (path, payload) => {
await refreshTokenIfNeeded()
return new Promise((resolve, reject) => {
request.post(
{
url: GOOGLE_API_ENDPOINT + path,
headers: {
"Content-type": "application/json",
Authorization: `Bearer ${googleTokens.access_token}`,
},
body: JSON.stringify(payload),
},
(error, response, body) => {
if (error) {
reject(error)
} else if (response.statusCode >= 400) {
reject(new HttpError(response.statusCode, response.statusMessage))
} else {
try {
resolve({
json: JSON.parse(body),
status: response.statusCode,
})
} catch (err) {
log(response.statusCode, response.statusMessage)
reject(err)
}
}
}
)
})
}
return { stream, post }
}