Skip to content

Commit 3ebb277

Browse files
author
sheepzh
committed
Refactor message listener
1 parent 87d7c95 commit 3ebb277

File tree

11 files changed

+243
-69
lines changed

11 files changed

+243
-69
lines changed

global.d.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,14 @@ declare namespace timer {
509509
| 'limitWaking'
510510
// @since 1.2.3
511511
| 'limitRemoved'
512+
// Request by content script
513+
// @since 1.3.0
514+
| "cs.isInWhitelist"
515+
| "cs.incVisitCount"
516+
| "cs.printTodayInfo"
517+
| "cs.getTodayInfo"
518+
| "cs.moreMinutes"
519+
| "cs.getLimitedRules"
512520
type ResCode = "success" | "fail" | "ignore"
513521

514522
/**
@@ -526,6 +534,10 @@ declare namespace timer {
526534
msg?: string
527535
data?: T
528536
}
537+
/**
538+
* @since 1.3.0
539+
*/
540+
type Handler<Req, Res> = (data: Req) => Promise<Res>
529541
/**
530542
* @since 0.8.4
531543
*/

src/app/components/limit/modify/form/time-limit.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ const timeInput = (valRef: Ref<number>, unit: string, maxVal: number) => h(ElCol
3535
clearable: true,
3636
onInput: (val: string) => handleInput(val, valRef, maxVal),
3737
onClear: () => valRef.value = undefined,
38-
placeholder: '0'
38+
placeholder: '0',
39+
class: 'limit-modify-time-limit-input'
3940
},
4041
{
4142
append: () => unit
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* Copyright (c) 2022-present Hengyang Zhang
3+
*
4+
* This software is released under the MIT License.
5+
* https://opensource.org/licenses/MIT
6+
*/
7+
8+
import TimeLimitItem from "@entity/time-limit-item"
9+
import limitService from "@service/limit-service"
10+
import optionService from "@service/option-service"
11+
import timerService from "@service/timer-service"
12+
import whitelistService from "@service/whitelist-service"
13+
import MessageDispatcher from "./message-dispatcher"
14+
15+
/**
16+
* Handle request from contentscript
17+
*
18+
* @param dispatcher message dispatcher
19+
*/
20+
export default function init(dispatcher: MessageDispatcher) {
21+
dispatcher
22+
// Increase the visit time
23+
.register<string, void>('cs.incVisitCount', async host => {
24+
timerService.addOneTime(host)
25+
})
26+
// Judge is in whitelist
27+
.register<string, boolean>('cs.isInWhitelist', host => whitelistService.include(host))
28+
// Need to print the information of today
29+
.register<void, boolean>('cs.printTodayInfo', async () => {
30+
const option = await optionService.getAllOption()
31+
return !!option.printInConsole
32+
})
33+
// Get today info
34+
.register<string, timer.stat.Result>('cs.getTodayInfo', host => {
35+
const now = new Date()
36+
return timerService.getResult(host, now)
37+
})
38+
// More minutes
39+
.register<string, timer.limit.Item[]>('cs.moreMinutes', url => limitService.moreMinutes(url))
40+
// cs.getLimitedRules
41+
.register<string, TimeLimitItem[]>('cs.getLimitedRules', url => limitService.getLimited(url))
42+
}

src/background/index.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,33 @@ import { openLog } from "../common/logger"
99
import WhitelistMenuManager from "./whitelist-menu-manager"
1010
import BrowserActionMenuManager from "./browser-action-menu-manager"
1111
import IconAndAliasCollector from "./icon-and-alias-collector"
12-
import MessageListener from "./message-listener"
1312
import Timer from "./timer"
1413
import VersionManager from "./version-manager"
1514
import ActiveTabListener from "./active-tab-listener"
1615
import badgeTextManager from "./badge-text-manager"
1716
import metaService from "@service/meta-service"
1817
import UninstallListener from "./uninstall-listener"
18+
import MessageDispatcher from "./message-dispatcher"
19+
import initLimitProcesser from "./limit-processor"
20+
import initCsHandler from "./content-script-handler"
1921

2022
// Open the log of console
2123
openLog()
2224

25+
const messageDispatcher = new MessageDispatcher()
26+
27+
// Limit processor
28+
initLimitProcesser(messageDispatcher)
29+
30+
// Content-script's request handler
31+
initCsHandler(messageDispatcher)
32+
2333
// Start the timer
2434
new Timer().start()
2535

2636
// Collect the icon url and title
2737
new IconAndAliasCollector().listen()
2838

29-
// Message listener
30-
new MessageListener().listen()
31-
3239
// Process version
3340
new VersionManager().init()
3441

@@ -52,3 +59,5 @@ chrome.runtime.onInstalled.addListener(async detail => {
5259
// Questionnaire for uninstall
5360
new UninstallListener().listen()
5461
})
62+
63+
messageDispatcher.start()

src/background/limit-processor.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Copyright (c) 2022-present Hengyang Zhang
3+
*
4+
* This software is released under the MIT License.
5+
* https://opensource.org/licenses/MIT
6+
*/
7+
8+
import { LIMIT_ROUTE } from "@app/router/constants"
9+
import TimeLimitItem from "@entity/time-limit-item"
10+
import { getAppPageUrl } from "@util/constant/url"
11+
import MessageDispatcher from "./message-dispatcher"
12+
13+
function processLimitWaking(rules: TimeLimitItem[], tab: chrome.tabs.Tab) {
14+
const { url } = tab
15+
const anyMatch = rules.map(rule => rule.matches(url)).reduce((a, b) => a || b, false)
16+
if (!anyMatch) {
17+
return
18+
}
19+
chrome.tabs.sendMessage<timer.mq.Request<timer.limit.Item[]>, timer.mq.Response>(tab.id, {
20+
code: "limitWaking",
21+
data: rules
22+
}, result => {
23+
if (result?.code === "fail") {
24+
console.error(`Failed to wake with limit rule: rules=${JSON.stringify(rules)}, msg=${result.msg}`)
25+
} else if (result?.code === "success") {
26+
console.log(`Waked tab[id=${tab.id}]`)
27+
}
28+
})
29+
}
30+
31+
export default function init(dispatcher: MessageDispatcher) {
32+
dispatcher
33+
.register<string, void>(
34+
'openLimitPage',
35+
async (url: string) => {
36+
const pageUrl = getAppPageUrl(true, LIMIT_ROUTE, { url: encodeURI(url) })
37+
chrome.tabs.create({ url: pageUrl })
38+
}
39+
)
40+
.register<timer.limit.Item[]>(
41+
'limitWaking',
42+
async data => {
43+
const rules = (data || [])
44+
.map(like => TimeLimitItem.of(like))
45+
chrome.tabs.query({ status: "complete" }, tabs => {
46+
tabs.forEach(tab => processLimitWaking(rules, tab))
47+
})
48+
}
49+
)
50+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { log } from "@src/common/logger"
2+
3+
/**
4+
* Copyright (c) 2022-present Hengyang Zhang
5+
*
6+
* This software is released under the MIT License.
7+
* https://opensource.org/licenses/MIT
8+
*/
9+
class MessageDispatcher {
10+
private handlers: Partial<{
11+
[code in timer.mq.ReqCode]: timer.mq.Handler<any, any>
12+
}> = {}
13+
14+
register<Req = any, Res = any>(code: timer.mq.ReqCode, handler: timer.mq.Handler<Req, Res>): MessageDispatcher {
15+
if (this.handlers[code]) {
16+
throw new Error("Duplicate handler")
17+
}
18+
this.handlers[code] = handler
19+
return this
20+
}
21+
22+
private async handle(message: timer.mq.Request<unknown>): Promise<timer.mq.Response<unknown>> {
23+
const code = message?.code
24+
if (!code) {
25+
return { code: 'ignore' }
26+
}
27+
const handler = this.handlers[code]
28+
if (!handler) {
29+
return { code: 'ignore' }
30+
}
31+
try {
32+
const result = await handler(message.data)
33+
return { code: 'success', data: result }
34+
} catch (error) {
35+
return { code: 'fail', msg: error }
36+
}
37+
}
38+
39+
start() {
40+
// Be careful!!!
41+
// Can't use await/async in callback parameter
42+
chrome.runtime.onMessage.addListener((message: timer.mq.Request<unknown>, _sender: never, sendResponse: timer.mq.Callback<unknown>) => {
43+
log('start to handle message', message.code, message.data)
44+
this.handle(message).then(response => {
45+
log('the response is', response, message)
46+
sendResponse(response)
47+
})
48+
// 'return ture' will force chrome to wait for the response processed in the above promise.
49+
// @see https://github.com/mozilla/webextension-polyfill/issues/130
50+
return true
51+
})
52+
}
53+
}
54+
55+
export default MessageDispatcher

src/background/message-listener.ts

Lines changed: 0 additions & 49 deletions
This file was deleted.

src/content-script/index.ts

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,52 @@
55
* https://opensource.org/licenses/MIT
66
*/
77

8-
import optionService from "@service/option-service"
9-
import timerService from "@service/timer-service"
10-
import whitelistService from "@service/whitelist-service"
118
import { initLocale } from "@util/i18n"
129
import processLimit from "./limit"
1310
import printInfo from "./printer"
1411

1512
const host = document.location.host
1613
const url = document.location.href
1714

15+
function isInWhitelist(host: string): Promise<boolean> {
16+
const request: timer.mq.Request<string> = {
17+
code: 'cs.isInWhitelist',
18+
data: host
19+
}
20+
return new Promise(resolve => chrome.runtime.sendMessage(request, {},
21+
(res: timer.mq.Response<boolean>) => resolve(res.code === 'success' && !!res.data)
22+
))
23+
}
24+
25+
function addOneTime(host: string): void {
26+
const request: timer.mq.Request<string> = {
27+
code: 'cs.incVisitCount',
28+
data: host
29+
}
30+
chrome.runtime.sendMessage(request, () => { })
31+
}
32+
33+
function printTodayInfo(): Promise<boolean> {
34+
const request: timer.mq.Request<void> = {
35+
code: 'cs.printTodayInfo',
36+
data: undefined
37+
}
38+
return new Promise(resolve => chrome.runtime.sendMessage(request,
39+
(res: timer.mq.Response<boolean>) => resolve(res.code === 'success' && !!res.data)
40+
))
41+
}
42+
1843
async function main() {
1944
if (!host) return
2045

21-
const isWhitelist = await whitelistService.include(host)
46+
const isWhitelist = await isInWhitelist(host)
2247
if (isWhitelist) return
2348

24-
timerService.addOneTime(host)
49+
addOneTime(host)
2550

2651
await initLocale()
27-
const option = await optionService.getAllOption()
28-
if (!!option.printInConsole) {
29-
printInfo(host)
30-
}
52+
const needPrintInfo = await printTodayInfo()
53+
!!needPrintInfo && printInfo(host)
3154
processLimit(url)
3255
}
3356

src/content-script/limit.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,28 @@
66
*/
77

88
import TimeLimitItem from "@entity/time-limit-item"
9-
import limitService from "@service/limit-service"
109
import { t2Chrome } from "@util/i18n/chrome/t"
1110

11+
function moreMinutes(url: string): Promise<timer.limit.Item[]> {
12+
const request: timer.mq.Request<string> = {
13+
code: 'cs.moreMinutes',
14+
data: url
15+
}
16+
return new Promise(resolve => chrome.runtime.sendMessage(request,
17+
(res: timer.mq.Response<timer.limit.Item[]>) => resolve(res?.code === 'success' ? res.data || [] : [])
18+
))
19+
}
20+
21+
function getLimited(url: string): Promise<timer.limit.Item[]> {
22+
const request: timer.mq.Request<string> = {
23+
code: 'cs.getLimitedRules',
24+
data: url
25+
}
26+
return new Promise(resolve => chrome.runtime.sendMessage(request,
27+
(res: timer.mq.Response<timer.limit.Item[]>) => resolve(res?.code === 'success' ? res.data || [] : [])
28+
))
29+
}
30+
1231
class _Modal {
1332
url: string
1433
mask: HTMLDivElement
@@ -36,7 +55,7 @@ class _Modal {
3655
const text = t2Chrome(msg => msg.message.more5Minutes)
3756
link.innerText = text
3857
link.onclick = async () => {
39-
const delayRules = await limitService.moreMinutes(_thisUrl)
58+
const delayRules = await moreMinutes(_thisUrl)
4059
const wakingRules = delayRules
4160
.map(like => TimeLimitItem.of(like))
4261
.filter(rule => !rule.hasLimited())
@@ -165,7 +184,7 @@ function handleLimitRemoved(msg: timer.mq.Request<void>, modal: _Modal): timer.m
165184

166185
export default async function processLimit(url: string) {
167186
const modal = new _Modal(url)
168-
const limitedRules: TimeLimitItem[] = await limitService.getLimited(url)
187+
const limitedRules: timer.limit.Item[] = await getLimited(url)
169188
if (limitedRules?.length) {
170189
window.onload = () => modal.showModal(!!limitedRules?.filter?.(item => item.allowDelay).length)
171190
}

0 commit comments

Comments
 (0)