Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: background ioc #90

Merged
merged 1 commit into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"test:ci": "pnpm test -- --reporters=default --reporters=github-actions"
},
"dependencies": {
"awilix": "^10.0.1",
"axios": "^1.5.1",
"class-variance-authority": "^0.7.0",
"clean-webpack-plugin": "^4.0.0",
Expand Down
11 changes: 11 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions src/background/Background.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { runtime, tabs } from 'webextension-polyfill'

import { PaymentFlowService } from '@/background/grantFlow'

import getSendingPaymentPointerHandler from '../messageHandlers/getSendingPaymentPointerHandler'
import isMonetizationReadyHandler from '../messageHandlers/isMonetizationReadyHandler'
import setIncomingPointerHandler from '../messageHandlers/setIncomingPointerHandler'
import { tabChangeHandler, tabUpdateHandler } from './tabHandlers'

class Background {
private messageHandlers: any = [
isMonetizationReadyHandler,
setIncomingPointerHandler,
getSendingPaymentPointerHandler,
]
private subscriptions: any = []
// TO DO: remove these from background into storage or state & use injection
grantFlow: PaymentFlowService | null = null
spentAmount: number = 0
paymentStarted = false

constructor() {}

subscribeToMessages() {
this.subscriptions = this.messageHandlers.map((handler: any) => {
const listener: any = async (message: EXTMessage) => {
if (handler.type === message.type) {
try {
await handler.callback(message.data, this)
} catch (error) {
console.log('[===== Error in MessageListener =====]', error)
return error
}
}
}

runtime.onMessage.addListener(listener)

return () => {
runtime.onMessage.removeListener(listener)
}
})
}

subscribeToTabChanges() {
//Add Update listener for tab
tabs.onUpdated.addListener(tabUpdateHandler)

//Add tab change listener
tabs.onActivated.addListener(tabChangeHandler)
}

unsubscribeFromMessages() {
this.subscriptions.forEach((sub: any) => sub())
}
}

export default Background
12 changes: 12 additions & 0 deletions src/background/BackgroundContainer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { asClass, createContainer } from 'awilix'

import Background from './Background'

const BackgroundContainer = createContainer()

BackgroundContainer.register({
Background: asClass(Background).singleton(),
// TODO - add injectable services
})

export default BackgroundContainer
266 changes: 8 additions & 258 deletions src/background/index.ts
Original file line number Diff line number Diff line change
@@ -1,264 +1,14 @@
import { action, Runtime, runtime, Tabs, tabs } from 'webextension-polyfill'
import BackgroundContainer from './BackgroundContainer'

import { PaymentFlowService } from '@/background/grantFlow'
const initialize = () => {
console.log('Start initialization')

const iconActive34 = runtime.getURL('assets/icons/icon-active-34.png')
const iconActive128 = runtime.getURL('assets/icons/icon-active-128.png')
const iconInactive34 = runtime.getURL('assets/icons/icon-inactive-34.png')
const iconInactive128 = runtime.getURL('assets/icons/icon-inactive-128.png')
const background = BackgroundContainer.resolve('Background')

// const SENDING_PAYMENT_POINTER_URL = 'https://ilp.rafiki.money/wmuser' // cel din extensie al userului
// const RECEIVING_PAYMENT_POINTER_URL = 'https://ilp.rafiki.money/web-page' // cel din dom
background.subscribeToMessages()
background.subscribeToTabChanges()

/**
* Define background script functions
* @type {class}
*/
class Background {
_port: number
grantFlow: PaymentFlowService | null = null
spentAmount: number = 0
paymentStarted = false

constructor() {
this.init()
}

/**
* Document Ready
*
* @returns {void}
*/
init = async () => {
console.log('[===== Loaded Background Scripts =====]')

//When extension installed
runtime.onInstalled.addListener(this.onInstalled)

//Add message listener in Browser.
runtime.onMessage.addListener(this.onMessage)

//Add Update listener for tab
tabs.onUpdated.addListener(this.onUpdatedTab)

//Add New tab create listener
tabs.onCreated.addListener(this.onCreatedTab)

//Add tab change listener
tabs.onActivated.addListener(this.handleTabChange)
}

//TODO: Listeners

/**
* Extension Installed
*/
onInstalled = () => {
console.log('[===== Installed Extension!] =====')
}

/**
* Message Handler Function
*
* @param message
* @param sender
* @returns
*/
onMessage = async (message: EXTMessage, sender: Runtime.MessageSender) => {
try {
console.log('[===== Received message =====]', message, sender)
switch (message.type) {
case 'IS_MONETIZATION_READY': {
if (message?.data) {
this.updateIcon(message.data.monetization)
}
break
}

case 'SET_INCOMING_POINTER': {
const {
incomingPayment: receivingPaymentPointerUrl,
paymentPointer: sendingPaymentPointerUrl,
amount,
} = message.data

if (this.grantFlow?.sendingPaymentPointerUrl === sendingPaymentPointerUrl) {
if (!this.paymentStarted) {
this.paymentStarted = true
const currentTabId = await this.grantFlow?.getCurrentActiveTabId()
await tabs.sendMessage(currentTabId ?? 0, { type: 'START_PAYMENTS' })
}
} else {
this.grantFlow = new PaymentFlowService(
sendingPaymentPointerUrl,
receivingPaymentPointerUrl,
amount,
)

this.grantFlow.initPaymentFlow()
}

break
}

case 'GET_SENDING_PAYMENT_POINTER': {
if (this.grantFlow) {
const { sendingPaymentPointerUrl, amount } = this.grantFlow
return {
type: 'SUCCESS',
data: { sendingPaymentPointerUrl, amount, started: this.paymentStarted },
}
}

return {
type: 'ERROR',
data: { sendingPaymentPointerUrl: '' },
}
}

case 'RUN_PAYMENT': {
if (this.grantFlow) {
this.grantFlow.sendPayment()
this.spentAmount = Number(
parseFloat(String(this.spentAmount + 1000000 / 10 ** 9)).toFixed(3),
)
this.sendSpendAmount()
this.paymentStarted = true
}
break
}

case 'PAUSE_PAYMENTS': {
this.paymentStarted = false
break
}
}

return true // result to reply
} catch (error) {
console.log('[===== Error in MessageListener =====]', error)
return error
}
}

/**
* Message from Long Live Connection
*
* @param msg
*/
onMessageFromExtension = (msg: EXTMessage) => {
console.log('[===== Message from Long Live Connection =====]', msg)
}

/**
*
* @param tab
*/
onCreatedTab = (tab: Tabs.Tab) => {
console.log('[===== New Tab Created =====]', tab)
}

sendSpendAmount() {
runtime.sendMessage({
type: 'SPENT_AMOUNT',
data: { spentAmount: this.spentAmount },
})
}

/**
* When changes tabs
*
* @param {*} tabId
* @param {*} changeInfo
* @param {*} tab
*/
onUpdatedTab = async (tabId: number, changeInfo: Tabs.OnUpdatedChangeInfoType, tab: Tabs.Tab) => {
if (tab.status === 'complete' && tab.url?.match(/^http/)) {
const response = await this.sendMessage(tab, { type: 'IS_MONETIZATION_READY' })
if (response.data) {
await this.updateIcon(response.data.monetization)
}
}
}

/**
* Get url from tabId
*
*/
getURLFromTab = async (tabId: number) => {
try {
const tab = await tabs.get(tabId)
return tab.url || ''
} catch (error) {
console.log(`[===== Could not get Tab Info$(tabId) in getURLFromTab =====]`, error)
throw ''
}
}

/**
* Open new tab by url
*
*/
openNewTab = async (url: string) => {
try {
const tab = await tabs.create({ url })
return tab
} catch (error) {
console.log(`[===== Error in openNewTab =====]`, error)
return null
}
}

/**
* Close specific tab
*
* @param {number} tab
*/
closeTab = async (tab: Tabs.Tab) => {
try {
await tabs.remove(tab.id ?? 0)
} catch (error) {
console.log(`[===== Error in closeTab =====]`, error)
}
}

/**
* send message
*/
sendMessage = async (tab: Tabs.Tab, msg: EXTMessage) => {
try {
const res = await tabs.sendMessage(tab.id ?? 0, msg)
return res
} catch (error) {
console.log(`[===== Error in sendMessage =====]`, error)
return null
}
}

updateIcon = async (active: boolean) => {
const iconData = {
'34': active ? iconActive34 : iconInactive34,
'128': active ? iconActive128 : iconInactive128,
}

if (action) {
await action.setIcon({ path: iconData })
} else if (chrome.browserAction) {
chrome.browserAction.setIcon({ path: iconData })
}
}

handleTabChange = async (activeInfo: chrome.tabs.TabActiveInfo) => {
const tabId = activeInfo.tabId

const tab = await tabs.get(tabId)
if (tab && tab.url?.includes('https') && tab.status === 'complete') {
const response = await this.sendMessage(tab, { type: 'IS_MONETIZATION_READY' })
if (response?.data) {
this.updateIcon(response.data.monetization)
}
}
}
console.log('End initialization')
}

export const background = new Background()
initialize()
Loading
Loading