Skip to content

Commit abd91e8

Browse files
committed
Use Gmail API client instead of IMAP client when account is created with API scopes
1 parent 4e6d1e4 commit abd91e8

File tree

3 files changed

+129
-65
lines changed

3 files changed

+129
-65
lines changed

lib/api-client/gmail-client.js

+96-49
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ const { oauth2Apps } = require('../oauth2-apps');
55
const getSecret = require('../get-secret');
66
const msgpack = require('msgpack5')();
77
const logger = require('../logger');
8-
const util = require('util');
98
const addressparser = require('nodemailer/lib/addressparser');
109
const libmime = require('libmime');
1110
const he = require('he');
1211

12+
const { REDIS_PREFIX } = require('../consts');
13+
1314
const fs = require('fs');
1415

1516
const GMAIL_API_BASE = 'https://gmail.googleapis.com';
@@ -68,8 +69,45 @@ class GmailClient {
6869
constructor(account, options) {
6970
this.account = account;
7071
this.options = options || {};
72+
73+
this.accountLogger = options.accountLogger;
7174
this.redis = options.redis;
7275
this.logger = options.logger || logger;
76+
77+
this.subconnections = [];
78+
}
79+
80+
async init() {
81+
// No-op
82+
}
83+
84+
async delete() {
85+
// No-op
86+
}
87+
88+
getAccountKey() {
89+
return `${REDIS_PREFIX}iad:${this.account}`;
90+
}
91+
92+
getMailboxListKey() {
93+
return `${REDIS_PREFIX}ial:${this.account}`;
94+
}
95+
96+
getMailboxHashKey() {
97+
return `${REDIS_PREFIX}iah:${this.account}`;
98+
}
99+
100+
getLogKey() {
101+
// this format ensures that the key is deleted when user is removed
102+
return `${REDIS_PREFIX}iam:${this.account}:g`;
103+
}
104+
105+
getLoggedAccountsKey() {
106+
return `${REDIS_PREFIX}iaz:logged`;
107+
}
108+
109+
currentState() {
110+
return 'connected';
73111
}
74112

75113
async getAccount() {
@@ -108,12 +146,13 @@ class GmailClient {
108146
}
109147

110148
async listMailboxes(options) {
149+
console.log('LIST MAILBOXES', options);
111150
await this.prepare();
112-
151+
console.log(1);
113152
const accessToken = await this.getToken();
114-
153+
console.log(2, accessToken);
115154
let labelsResult = await this.oAuth2Client.request(accessToken, `${GMAIL_API_BASE}/gmail/v1/users/me/labels`);
116-
155+
console.log(3, labelsResult);
117156
let labels = labelsResult.labels.filter(label => !SKIP_LABELS.includes(label.id));
118157

119158
let resultLabels;
@@ -127,7 +166,9 @@ class GmailClient {
127166
resultLabels = labels;
128167
}
129168

130-
resultLabels = resultLabels
169+
console.log(3, resultLabels);
170+
171+
let mailboxes = resultLabels
131172
.map(label => {
132173
let pathParts = label.name.split('/');
133174
let name = pathParts.pop();
@@ -191,8 +232,9 @@ class GmailClient {
191232

192233
return a.path.toLowerCase().localeCompare(b.path.toLowerCase());
193234
});
235+
console.log(555, mailboxes);
194236

195-
return { mailboxes: resultLabels };
237+
return mailboxes;
196238
}
197239

198240
getEnvelope(messageData) {
@@ -433,6 +475,7 @@ class GmailClient {
433475
}
434476

435477
async listMessages(query) {
478+
console.log('LIST MESSAGES', query);
436479
await this.prepare();
437480

438481
const accessToken = await this.getToken();
@@ -711,62 +754,66 @@ class GmailClient {
711754

712755
module.exports = { GmailClient };
713756

714-
const { redis } = require('../db');
757+
if (/gmail-client\.js$/.test(process.argv[1])) {
758+
console.log('RUN AS STANDALONE');
715759

716-
let main = async () => {
717-
let gmailClient = new GmailClient('andris', { redis });
760+
let main = async () => {
761+
const { redis } = require('../db');
718762

719-
let mailboxes = await gmailClient.listMailboxes();
720-
console.log(mailboxes);
763+
let gmailClient = new GmailClient('andris', { redis });
721764

722-
let messages = await gmailClient.listMessages({ path: 'INBOX' });
723-
console.log(JSON.stringify(messages, false, 2));
765+
let mailboxes = await gmailClient.listMailboxes();
766+
console.log(mailboxes);
724767

725-
let deleted = false;
768+
let messages = await gmailClient.listMessages({ path: 'INBOX' });
769+
console.log(JSON.stringify(messages, false, 2));
726770

727-
for (let msg of messages) {
728-
if (/testkiri/i.test(msg.subject) && !deleted) {
729-
deleted = true;
771+
let deleted = false;
730772

731-
console.log('DELETING', msg.id);
732-
let y = await gmailClient.deleteMessage(msg.id, true);
733-
console.log('DELETE RESULT', y);
734-
}
773+
for (let msg of messages) {
774+
if (/testkiri/i.test(msg.subject) && !deleted) {
775+
deleted = true;
776+
777+
console.log('DELETING', msg.id);
778+
let y = await gmailClient.deleteMessage(msg.id, true);
779+
console.log('DELETE RESULT', y);
780+
}
735781

736-
if (msg.attachments && msg.attachments.length) {
737-
await gmailClient.getMessage(msg.id, { textType: '*' });
782+
if (msg.attachments && msg.attachments.length) {
783+
await gmailClient.getMessage(msg.id, { textType: '*' });
738784

739-
const textContent = await gmailClient.getText(msg.text.id, { textType: '*' });
740-
console.log('TEXT CONTENT', textContent);
785+
const textContent = await gmailClient.getText(msg.text.id, { textType: '*' });
786+
console.log('TEXT CONTENT', textContent);
741787

742-
console.log('MOVE MESSAGE');
743-
let moveRes = await gmailClient.moveMessage(msg.id, { path: 'Inbox' });
744-
console.log('MOVE RES', moveRes);
788+
console.log('MOVE MESSAGE');
789+
let moveRes = await gmailClient.moveMessage(msg.id, { path: 'Inbox' });
790+
console.log('MOVE RES', moveRes);
745791

746-
let raw = await gmailClient.getRawMessage(msg.id);
747-
await fs.promises.writeFile(`/Users/andris/Desktop/${msg.id}.eml`, raw);
748-
for (let a of msg.attachments) {
749-
let attachment = await gmailClient.getAttachment(a.id);
750-
console.log(attachment);
751-
let s = fs.createWriteStream(`/Users/andris/Desktop/${a.filename}`);
792+
let raw = await gmailClient.getRawMessage(msg.id);
793+
await fs.promises.writeFile(`/Users/andris/Desktop/${msg.id}.eml`, raw);
794+
for (let a of msg.attachments) {
795+
let attachment = await gmailClient.getAttachment(a.id);
796+
console.log(attachment);
797+
let s = fs.createWriteStream(`/Users/andris/Desktop/${a.filename}`);
752798

753-
console.log('PIPING TO STREAM');
754-
await new Promise((r, e) => {
755-
s.once('finish', r);
756-
s.once('error', e);
799+
console.log('PIPING TO STREAM');
800+
await new Promise((r, e) => {
801+
s.once('finish', r);
802+
s.once('error', e);
757803

758-
s.write(attachment.data);
759-
s.end();
760-
});
761-
console.log('DONE');
804+
s.write(attachment.data);
805+
s.end();
806+
});
807+
console.log('DONE');
762808

763-
//await fs.promises.writeFile(`/Users/andris/Desktop/${a.filename}`, attachment);
764-
process.exit();
809+
//await fs.promises.writeFile(`/Users/andris/Desktop/${a.filename}`, attachment);
810+
process.exit();
811+
}
765812
}
766813
}
767-
}
768-
};
814+
};
769815

770-
main()
771-
.catch(err => console.error(util.inspect(err, false, 22)))
772-
.finally(() => process.exit());
816+
main()
817+
.catch(err => console.error(require('util').inspect(err, false, 22)))
818+
.finally(() => process.exit());
819+
}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"scripts": {
99
"start": "node server.js",
1010
"dev": "EE_OPENAPI_VERBOSE=true EENGINE_LOG_RAW=true node --tls-keylog=keylog.txt server --dbs.redis='redis://127.0.0.1:6379/9' --api.port=7003 --api.host=0.0.0.0 | tee $HOME/ee.log.dev.txt | pino-pretty",
11-
"single": "EE_OPENAPI_VERBOSE=true EENGINE_LOG_RAW=true EENGINE_WORKERS=1 node --inspect server --dbs.redis='redis://127.0.0.1:6379/10' --api.port=7009 --api.host=0.0.0.0 | tee $HOME/ee.log.single.txt | pino-pretty",
11+
"single": "EE_OPENAPI_VERBOSE=true EENGINE_LOG_RAW=true EENGINE_WORKERS=1 node --inspect server --dbs.redis='redis://127.0.0.1:6379/10' --api.port=7003 --api.host=0.0.0.0 | tee $HOME/ee.log.single.txt | pino-pretty",
1212
"gmail": "EE_OPENAPI_VERBOSE=true EENGINE_LOG_RAW=true EENGINE_FEATURE_GMAIL_API=true EENGINE_WORKERS=1 node --inspect server --dbs.redis='redis://127.0.0.1:6379/11' --api.port=7003 --api.host=0.0.0.0 | tee $HOME/ee.log.gmail.txt | pino-pretty",
1313
"test": "grunt && node --test test/",
1414
"swagger": "./getswagger.sh",

workers/imap.js

+32-15
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ if (readEnvValue('BUGSNAG_API_KEY')) {
3333
}
3434

3535
const { Connection } = require('../lib/connection');
36+
const { GmailClient } = require('../lib/api-client/gmail-client');
3637
const { Account } = require('../lib/account');
38+
const { oauth2Apps } = require('../lib/oauth2-apps');
3739
const { redis, notifyQueue, submitQueue, documentsQueue, getFlowProducer } = require('../lib/db');
3840
const { MessagePortWritable } = require('../lib/message-port-stream');
3941
const { getESClient } = require('../lib/document-store');
@@ -138,22 +140,37 @@ class ConnectionHandler {
138140
});
139141

140142
this.accounts.set(account, accountObject);
141-
accountObject.connection = new Connection({
142-
account,
143-
accountObject,
144-
redis,
145-
secret,
146-
notifyQueue,
147-
submitQueue,
148-
documentsQueue,
149-
flowProducer,
150-
accountLogger,
151-
call: msg => this.call(msg),
152-
logRaw: EENGINE_LOG_RAW
153-
});
154-
accountObject.logger = accountObject.connection.logger;
155143

156-
let accountData = await accountObject.loadAccountData();
144+
const accountData = await accountObject.loadAccountData();
145+
146+
if (accountData.oauth2 && accountData.oauth2.auth) {
147+
const oauth2App = await oauth2Apps.get(accountData.oauth2.provider);
148+
if (oauth2App.baseScopes === 'api') {
149+
// Use API instead of IMAP
150+
accountObject.connection = new GmailClient(account, {
151+
redis,
152+
accountLogger
153+
});
154+
accountData.state = 'connected';
155+
}
156+
}
157+
158+
if (!accountObject.connection) {
159+
accountObject.connection = new Connection({
160+
account,
161+
accountObject,
162+
redis,
163+
secret,
164+
notifyQueue,
165+
submitQueue,
166+
documentsQueue,
167+
flowProducer,
168+
accountLogger,
169+
call: msg => this.call(msg),
170+
logRaw: EENGINE_LOG_RAW
171+
});
172+
accountObject.logger = accountObject.connection.logger;
173+
}
157174

158175
if (accountData.state) {
159176
await redis.hSetExists(accountObject.connection.getAccountKey(), 'state', accountData.state);

0 commit comments

Comments
 (0)