Skip to content

Commit

Permalink
refactor(background): split up OpenPaymentsService (#775)
Browse files Browse the repository at this point in the history
- related grant and AcessToken functionality moved to `OutgoingPaymentGrantService`
   -  provides a service for managing outgoing payment grants, including creating, canceling, and rotating grants, as well as switching between different grant types.
-  move `connectWallet`, `addFunds`, `updateBudget`, `disconnectWallet` and related to new `WalletService`
- move `createOutgoingPayment`, `pollOutgoingPayment` and `probeDebitAmount` to `PaymentSession`
- move close popup event from openPayments to wallet service


Co-authored-by: Sid Vishnoi <[email protected]>
  • Loading branch information
DarianM and sidvishnoi authored Jan 9, 2025
1 parent 0413c96 commit ce6d58f
Show file tree
Hide file tree
Showing 11 changed files with 1,163 additions and 958 deletions.
12 changes: 11 additions & 1 deletion jest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@ import '@testing-library/jest-dom';

import { chrome } from 'jest-chrome';

Object.assign(global, { chrome: chrome, browser: chrome });
jest.mock('./src/shared/defines', () => ({
LOG_LEVEL: 'debug',
PERMISSION_HOSTS: { origins: ['http://*/*', 'https://*/*'] },
ALLOWED_PROTOCOLS: ['http:', 'https:'],
OPEN_PAYMENTS_REDIRECT_URL: 'https://webmonetization.org/welcome',
}));

Object.assign(global, {
chrome: chrome,
browser: chrome,
});
16 changes: 15 additions & 1 deletion src/background/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import browser, { type Browser } from 'webextension-polyfill';
import {
OpenPaymentsService,
StorageService,
WalletService,
MonetizationService,
Background,
TabEvents,
Expand All @@ -17,7 +18,8 @@ import {
EventsService,
Heartbeat,
Deduplicator,
} from './services';
OutgoingPaymentGrantService,
} from '@/background/services';
import { createLogger, Logger } from '@/shared/logger';
import { LOG_LEVEL } from '@/shared/defines';
import {
Expand All @@ -39,7 +41,9 @@ export interface Cradle {
events: EventsService;
deduplicator: Deduplicator;
storage: StorageService;
outgoingPaymentGrantService: OutgoingPaymentGrantService;
openPaymentsService: OpenPaymentsService;
walletService: WalletService;
monetizationService: MonetizationService;
message: MessageManager<BackgroundToContentMessage>;
sendToPopup: SendToPopup;
Expand Down Expand Up @@ -75,11 +79,21 @@ export const configureContainer = () => {
.inject(() => ({
logger: logger.getLogger('storage'),
})),
outgoingPaymentGrantService: asClass(OutgoingPaymentGrantService)
.singleton()
.inject(() => ({
logger: logger.getLogger('outgoing-payment-grant'),
})),
openPaymentsService: asClass(OpenPaymentsService)
.singleton()
.inject(() => ({
logger: logger.getLogger('open-payments'),
})),
walletService: asClass(WalletService)
.singleton()
.inject(() => ({
logger: logger.getLogger('wallet'),
})),
monetizationService: asClass(MonetizationService)
.singleton()
.inject(() => ({
Expand Down
26 changes: 13 additions & 13 deletions src/background/services/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
isErrorWithKey,
success,
} from '@/shared/helpers';
import { KeyAutoAddService } from './keyAutoAdd';
import { KeyAutoAddService } from '@/background/services/keyAutoAdd';
import { OpenPaymentsClientError } from '@interledger/open-payments/dist/client/error';
import { getTab } from '@/background/utils';
import { PERMISSION_HOSTS } from '@/shared/defines';
Expand All @@ -20,7 +20,7 @@ const ALARM_RESET_OUT_OF_FUNDS = 'reset-out-of-funds';

export class Background {
private browser: Cradle['browser'];
private openPaymentsService: Cradle['openPaymentsService'];
private walletService: Cradle['walletService'];
private monetizationService: Cradle['monetizationService'];
private storage: Cradle['storage'];
private logger: Cradle['logger'];
Expand All @@ -32,7 +32,7 @@ export class Background {

constructor({
browser,
openPaymentsService,
walletService,
monetizationService,
storage,
logger,
Expand All @@ -44,7 +44,7 @@ export class Background {
}: Cradle) {
Object.assign(this, {
browser,
openPaymentsService,
walletService,
monetizationService,
storage,
sendToPopup,
Expand Down Expand Up @@ -196,34 +196,34 @@ export class Background {
),
);

case 'CONNECT_WALLET':
await this.openPaymentsService.connectWallet(message.payload);
case 'CONNECT_WALLET': {
await this.walletService.connectWallet(message.payload);
if (message.payload?.recurring) {
this.scheduleResetOutOfFundsState();
}
return success(undefined);

}
case 'RECONNECT_WALLET': {
await this.openPaymentsService.reconnectWallet(message.payload);
await this.walletService.reconnectWallet(message.payload);
await this.monetizationService.resumePaymentSessionActiveTab();
await this.updateVisualIndicatorsForCurrentTab();
return success(undefined);
}

case 'UPDATE_BUDGET':
await this.openPaymentsService.updateBudget(message.payload);
await this.walletService.updateBudget(message.payload);
return success(undefined);

case 'ADD_FUNDS':
await this.openPaymentsService.addFunds(message.payload);
await this.walletService.addFunds(message.payload);
await this.browser.alarms.clear(ALARM_RESET_OUT_OF_FUNDS);
if (message.payload.recurring) {
this.scheduleResetOutOfFundsState();
}
return;

case 'DISCONNECT_WALLET':
await this.openPaymentsService.disconnectWallet();
await this.walletService.disconnectWallet();
await this.browser.alarms.clear(ALARM_RESET_OUT_OF_FUNDS);
await this.updateVisualIndicatorsForCurrentTab();
this.sendToPopup.send('SET_STATE', { state: {}, prevState: {} });
Expand Down Expand Up @@ -332,7 +332,7 @@ export class Background {
this.sendToPopup.send('SET_TRANSIENT_STATE', state);
});

this.events.on('connect_wallet.close_popup', () => {
this.events.on('wallet.close_popup', () => {
this.sendToPopup.send('CLOSE_POPUP', undefined);
});

Expand All @@ -347,7 +347,7 @@ export class Background {
this.logger.info(data);
if (details.reason === 'install') {
await this.storage.populate();
await this.openPaymentsService.generateKeys();
await this.walletService.generateKeys();
await this.browser.tabs.create({
url: this.browser.runtime.getURL(`${APP_URL}#/post-install`),
});
Expand Down
2 changes: 1 addition & 1 deletion src/background/services/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface BackgroundEvents {
'open_payments.key_revoked': void;
'open_payments.out_of_funds': void;
'open_payments.invalid_receiver': { tabId: number };
'connect_wallet.close_popup': void;
'wallet.close_popup': void;
'storage.rate_of_pay_update': { rate: string };
'storage.state_update': {
state: Storage['state'];
Expand Down
2 changes: 2 additions & 0 deletions src/background/services/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export { OpenPaymentsService } from './openPayments';
export { StorageService } from './storage';
export { MonetizationService } from './monetization';
export { OutgoingPaymentGrantService } from './outgoingPaymentGrant';
export { WalletService } from './wallet';
export { Background } from './background';
export { TabEvents } from './tabEvents';
export { TabState } from './tabState';
Expand Down
28 changes: 19 additions & 9 deletions src/background/services/monetization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
StopMonetizationPayload,
} from '@/shared/messages';
import { PaymentSession } from './paymentSession';
import { computeRate, getSender, getTabId } from '../utils';
import { computeRate, getSender, getTabId } from '@/background/utils';
import { isOutOfBalanceError } from './openPayments';
import {
OUTGOING_PAYMENT_POLLING_MAX_ATTEMPTS,
Expand All @@ -23,14 +23,14 @@ import {
} from '@/shared/helpers';
import type { AmountValue, PopupStore, Storage } from '@/shared/types';
import type { OutgoingPayment } from '@interledger/open-payments';
import type { Cradle } from '../container';
import type { Cradle } from '@/background/container';

export class MonetizationService {
private logger: Cradle['logger'];
private t: Cradle['t'];
private openPaymentsService: Cradle['openPaymentsService'];
private outgoingPaymentGrantService: Cradle['outgoingPaymentGrantService'];
private storage: Cradle['storage'];
private browser: Cradle['browser'];
private events: Cradle['events'];
private tabState: Cradle['tabState'];
private windowState: Cradle['windowState'];
Expand All @@ -39,10 +39,10 @@ export class MonetizationService {
constructor({
logger,
t,
browser,
openPaymentsService,
outgoingPaymentGrantService,
storage,
events,
openPaymentsService,
tabState,
windowState,
message,
Expand All @@ -51,8 +51,8 @@ export class MonetizationService {
logger,
t,
openPaymentsService,
outgoingPaymentGrantService,
storage,
browser,
events,
tabState,
windowState,
Expand Down Expand Up @@ -114,7 +114,9 @@ export class MonetizationService {
requestId,
tabId,
frameId,
this.storage,
this.openPaymentsService,
this.outgoingPaymentGrantService,
this.events,
this.tabState,
removeQueryParams(url!),
Expand Down Expand Up @@ -346,14 +348,19 @@ export class MonetizationService {
[...outgoingPayments]
.filter(([, outgoingPayment]) => outgoingPayment !== null)
.map(async ([sessionId, outgoingPaymentInitial]) => {
for await (const outgoingPayment of this.openPaymentsService.pollOutgoingPayment(
const session = payableSessions.find((s) => s.id === sessionId);
if (!session) {
this.logger.error('Could not find session for outgoing payment.');
return null;
}
for await (const outgoingPayment of session.pollOutgoingPayment(
// Null assertion: https://github.com/microsoft/TypeScript/issues/41173
outgoingPaymentInitial!.id,
{ signal, maxAttempts: OUTGOING_PAYMENT_POLLING_MAX_ATTEMPTS },
)) {
outgoingPayments.set(sessionId, outgoingPayment);
}
return outgoingPayments.get(sessionId)!;
return outgoingPayments.get(sessionId);
}),
);

Expand Down Expand Up @@ -418,7 +425,10 @@ export class MonetizationService {
if (!connected) return false;
if (isOkState(state)) return true;

if (state.out_of_funds && this.openPaymentsService.isAnyGrantUsable()) {
if (
state.out_of_funds &&
this.outgoingPaymentGrantService.isAnyGrantUsable
) {
// if we're in out_of_funds state, we still try to make payments hoping we
// have funds available now. If a payment succeeds, we move out from
// of_out_funds state.
Expand Down
Loading

0 comments on commit ce6d58f

Please sign in to comment.