This commit is contained in:
parent
53187bede7
commit
ef1e3e2d40
24
src/email.ts
24
src/email.ts
@ -14,7 +14,7 @@ interface ImapClientI {
|
||||
connect: () => Promise<void>;
|
||||
getMailboxLock: (mailbox: string) => Promise<MailboxLockObject>;
|
||||
messageDelete: (uids: number[], opts: Record<string, any>) => Promise<boolean>;
|
||||
close: () => void;
|
||||
logout: () => Promise<void>;
|
||||
}
|
||||
|
||||
type Email = {
|
||||
@ -26,13 +26,16 @@ type Email = {
|
||||
|
||||
class ErrorWithLock extends Error {
|
||||
lock: O.Option<MailboxLockObject>;
|
||||
constructor(message: string, lock?: MailboxLockObject) {
|
||||
imap: O.Option<ImapClientI>;
|
||||
constructor(message: string, lock?: MailboxLockObject, imap?: ImapClientI) {
|
||||
super(message);
|
||||
this.lock = O.fromNullable(lock);
|
||||
this.imap = O.fromNullable(imap);
|
||||
}
|
||||
}
|
||||
const ToErrorWithLock = (lock?: MailboxLockObject) => (error: unknown) =>
|
||||
new ErrorWithLock(error instanceof Error ? error.message : "Unknown error", lock);
|
||||
|
||||
const ToErrorWithLock = (lock?: MailboxLockObject, imap?: ImapClientI) => (error: unknown) =>
|
||||
new ErrorWithLock(error instanceof Error ? error.message : "Unknown error", lock, imap);
|
||||
|
||||
/**
|
||||
* Generate a unique email.
|
||||
@ -203,19 +206,19 @@ export const perform = (
|
||||
// act.
|
||||
TE.tap(({ email }) => pipe(getSendImpl(from)(email), TE.mapLeft(ToErrorWithLock()))),
|
||||
TE.bind("imap", () => pipe(getImapImpl(to), TE.mapLeft(ToErrorWithLock()))),
|
||||
TE.bind("mailboxLock", ({ imap }) => TE.tryCatch(() => imap.getMailboxLock("INBOX"), ToErrorWithLock())),
|
||||
TE.bind("mailboxLock", ({ imap }) => TE.tryCatch(() => imap.getMailboxLock("INBOX"), ToErrorWithLock(undefined, imap))),
|
||||
// "assert".
|
||||
TE.bind("uid", ({ imap, email, mailboxLock }) =>
|
||||
pipe(
|
||||
findEmailUidInInboxImpl(imap, matchesEmailImpl(email), retries, interval),
|
||||
TE.mapLeft(ToErrorWithLock(mailboxLock))
|
||||
TE.mapLeft(ToErrorWithLock(mailboxLock, imap))
|
||||
)
|
||||
),
|
||||
// cleanup.
|
||||
TE.bind("deleted", ({ imap, uid, mailboxLock }) =>
|
||||
TE.tryCatch(
|
||||
() => imap.messageDelete([uid], { uid: true }),
|
||||
ToErrorWithLock(mailboxLock),
|
||||
ToErrorWithLock(mailboxLock, imap),
|
||||
),
|
||||
),
|
||||
TE.fold(
|
||||
@ -223,10 +226,15 @@ export const perform = (
|
||||
if (O.isSome(e.lock)) {
|
||||
e.lock.value.release();
|
||||
}
|
||||
if (O.isSome(e.imap)) {
|
||||
const imap = e.imap.value;
|
||||
return pipe(TE.tryCatch(() => imap.logout(), toError), TE.flatMap(() => TE.left(e)));
|
||||
}
|
||||
return TE.left(e);
|
||||
},
|
||||
({ mailboxLock, deleted }) => {
|
||||
({ mailboxLock, deleted, imap }) => {
|
||||
mailboxLock.release();
|
||||
imap.logout();
|
||||
return TE.right(deleted);
|
||||
}
|
||||
)
|
||||
|
@ -31,7 +31,7 @@ const getMocks = () => {
|
||||
connect: mock(() => Promise.resolve()),
|
||||
getMailboxLock: mock(() => Promise.resolve(lock)),
|
||||
messageDelete: mock(() => Promise.resolve(true)),
|
||||
close: mock(() => constVoid()),
|
||||
logout: mock(() => Promise.resolve()),
|
||||
};
|
||||
|
||||
const mockDependencies: Partial<EmailJobDependencies> = {
|
||||
@ -116,6 +116,7 @@ test("releases lock on left", async () => {
|
||||
TE.mapLeft(() => {
|
||||
expect(imap.getMailboxLock).toHaveBeenCalledTimes(1);
|
||||
expect(lock.release).toHaveBeenCalledTimes(1);
|
||||
expect(imap.logout).toHaveBeenCalledTimes(1);
|
||||
}),
|
||||
)();
|
||||
});
|
||||
@ -131,6 +132,7 @@ test("releases lock on right", async () => {
|
||||
TE.map(() => {
|
||||
expect(imap.getMailboxLock).toHaveBeenCalledTimes(1);
|
||||
expect(lock.release).toHaveBeenCalledTimes(1);
|
||||
expect(imap.logout).toHaveBeenCalledTimes(1);
|
||||
}),
|
||||
TE.mapLeft(() => expect(false).toBeTruthy()),
|
||||
)();
|
||||
|
Loading…
Reference in New Issue
Block a user