Skip to content

Commit f34428f

Browse files
committed
merge with master
2 parents a2927eb + aeb4336 commit f34428f

File tree

18 files changed

+350
-133
lines changed

18 files changed

+350
-133
lines changed

.gitignore

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
.DS_Store
12
node_modules
23
.nyc_output
3-
.DS_Store
44
*.log
5-
.vscode
6-
.idea
75
.awcache
86
.rpt2_cache
7+
.nx
8+
9+
# IDEA files
10+
.idea
11+
12+
# VS code settings and workspace project
13+
.vscode
914
tsurlfilter.code-workspace

packages/adguard-api/CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.1.2] - 2024-02-08
9+
10+
### Added
11+
- New private method `removeObsoletedFilters` to prevent usage of obsoleted filters.
12+
- New public event channel `AdguardApi.onFiltersDeletion`.
13+
14+
### Changed
15+
- `adguardApi.start` returns Promise with applied configuration with already removed
16+
obsoleted filters ids.
17+
818
## [2.1.1] - 2023-12-01
919

1020
### Added

packages/adguard-api/README.md

+32-2
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,12 @@ const handleAppMessage = async (message: Message) => {
195195
};
196196

197197
// route message depending on handler name
198-
browser.runtime.onMessage.addListener(async (message, sender) => {
198+
browser.runtime.onMessage.addListener(async (message, sender) => {
199199
if (message?.handlerName === MESSAGE_HANDLER_NAME) {
200200
return Promise.resolve(handleApiMessage(message, sender));
201201
}
202202
return handleAppMessage(message);
203-
});
203+
});
204204
```
205205

206206
**Returns:**
@@ -405,6 +405,36 @@ adguardApi.onAssistantCreateRule.subscribe(applyRule);
405405
adguardApi.onAssistantCreateRule.unsubscribe(applyRule);
406406
```
407407

408+
### `adguardApi.onFiltersDeletion`
409+
410+
TsWebExtension Event channel, which fires event on obsoleted filters deletion.
411+
It can be fired after checking an update for filters in the FiltersUpdateService.
412+
413+
**Syntax:**
414+
415+
```typescript
416+
public onFiltersDeletion: EventChannel<number[]>;
417+
```
418+
419+
**Example:**
420+
421+
```typescript
422+
423+
// update config on filter deletion
424+
const removeObsoletedFilterId = async (filterIds: number[]): Promise<void> => {
425+
console.log(`Filters with ids ${filterIds} deleted because they became obsoleted.`);
426+
configuration.filters = configuration.filters.filter((id) => !filterIds.includes(id));
427+
428+
await adguardApi.configure(configuration);
429+
};
430+
431+
// add listener
432+
adguardApi.onFiltersDeletion.subscribe(removeObsoletedFilterId);
433+
434+
// remove listener
435+
adguardApi.onFiltersDeletion.unsubscribe(removeObsoletedFilterId);
436+
```
437+
408438
### `adguardApi.onRequestBlocking`
409439

410440
API for adding and removing listeners for request blocking events.

packages/adguard-api/package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{
22
"name": "@adguard/api",
3-
"version": "2.1.1",
3+
"version": "2.1.2",
44
"description": "This is a TypeScript library that implements AdGuard's extension API",
55
"main": "dist/adguard-api.js",
6-
"files": ["dist/**/*"],
6+
"files": [
7+
"dist/**/*"
8+
],
79
"typings": "dist/types/background/index.d.ts",
810
"exports": {
911
".": "./dist/adguard-api.js",

packages/adguard-api/src/background/filters/api.ts

+56-4
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,17 @@ export class FiltersApi {
5353
}
5454

5555
/**
56-
* Initializes linked APIs
56+
* Initializes linked APIs.
57+
*
58+
* @param filterIds IDs of filters to check for possible obsoleting.
59+
*
60+
* @returns List of outdated filters ids.
5761
*/
58-
public async init(): Promise<void> {
62+
public async init(filterIds: number[]): Promise<number[]> {
5963
await this.metadataApi.init();
6064
await this.versionsApi.init();
65+
66+
return this.removeObsoleteFilters(filterIds);
6167
}
6268

6369
/**
@@ -113,16 +119,21 @@ export class FiltersApi {
113119
* If filter version in metadata is higher, downloads and saves new rules content
114120
*
115121
* Dispatches {@link NotifierEventType.UpdateFilters} event, if at least one filter has been updated
122+
*
123+
* @returns List of outdated filters ids.
116124
*/
117-
public async updateFilters(): Promise<void> {
125+
public async updateFilters(): Promise<number[]> {
118126
this.logger.info("Update filters");
119127
/**
120128
* Reload filters metadata from backend for correct
121129
* version matching on update check.
122130
*/
123131
await this.metadataApi.loadMetadata();
124132

125-
const ids = this.versionsApi.getInstalledFilters();
133+
const installedFilterIds = this.versionsApi.getInstalledFilters();
134+
const obsoletedFiltersIds = await this.removeObsoleteFilters(installedFilterIds);
135+
136+
const ids = installedFilterIds.filter((id) => !obsoletedFiltersIds.includes(id));
126137

127138
const updateTasks = ids.map(async (id) => this.updateFilter(id));
128139

@@ -131,6 +142,47 @@ export class FiltersApi {
131142
if (updatedFilters.some((filterData) => !!filterData?.filterId)) {
132143
notifier.publishEvent({ type: NotifierEventType.UpdateFilters });
133144
}
145+
146+
return obsoletedFiltersIds;
147+
}
148+
149+
/**
150+
* Remove if necessary obsolete filters.
151+
*
152+
* @param filterIds IDs of filters to check for possible obsoleting.
153+
*
154+
* @returns List of outdated filters ids.
155+
*/
156+
private async removeObsoleteFilters(filterIds: number[]): Promise<number[]> {
157+
const installedFilterIds = this.versionsApi.getInstalledFilters();
158+
const metadataFiltersIds = this.metadataApi.getFiltersMetadata().map(({ filterId }) => filterId);
159+
160+
const obsoletedFiltersIds = filterIds.filter((id) => !metadataFiltersIds.includes(id));
161+
162+
const tasks = obsoletedFiltersIds.map(async (id) => {
163+
if (installedFilterIds.includes(id)) {
164+
await this.versionsApi.delete(id);
165+
await this.filterRulesApi.remove(id);
166+
167+
this.logger.info(`Obsoleted filter with id: ${id} removed from the storage`);
168+
}
169+
});
170+
171+
const promises = await Promise.allSettled(tasks);
172+
// Handles errors
173+
promises.forEach((promise) => {
174+
if (promise.status === "rejected") {
175+
this.logger.error("Cannot remove obsoleted filter from storage due to: ", promise.reason);
176+
}
177+
});
178+
179+
// Notify top-level about deletion of obsoleted filters.
180+
notifier.publishEvent({
181+
type: NotifierEventType.DeleteFilters,
182+
data: { filtersIds: obsoletedFiltersIds },
183+
});
184+
185+
return obsoletedFiltersIds;
134186
}
135187

136188
/**

packages/adguard-api/src/background/filters/rules.ts

+9
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ export class FilterRulesApi {
4949
await this.storage.set(FilterRulesApi.getFilterKey(filterId), rules);
5050
}
5151

52+
/**
53+
* Removes specified filter list from {@link storage}.
54+
*
55+
* @param filterId Filter id.
56+
*/
57+
async remove(filterId: number): Promise<void> {
58+
await this.storage.remove(FilterRulesApi.getFilterKey(filterId));
59+
}
60+
5261
/**
5362
* Generates {@link Storage} key for specified filter rules
5463
*

packages/adguard-api/src/background/filters/versions.ts

+16
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ export class VersionsApi {
109109
await this.saveData();
110110
}
111111

112+
/**
113+
* Deletes specified filter version.
114+
*
115+
* @param filterId Filter id.
116+
* @throws Error if filter version data is not initialized.
117+
*/
118+
public async delete(filterId: number): Promise<void> {
119+
if (!this.versions) {
120+
throw new Error("Filter versions are not initialized");
121+
}
122+
123+
delete this.versions[filterId];
124+
125+
await this.saveData();
126+
}
127+
112128
/**
113129
* Save data in extension storage
114130
*/

packages/adguard-api/src/background/main.ts

+36-7
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@
1919
import {
2020
type TsWebExtension,
2121
type ConfigurationMV2 as TsWebExtensionConfiguration,
22-
type EventChannel,
2322
type MessageHandlerMV2,
23+
EventChannel,
2424
createTsWebExtension,
2525
} from "@adguard/tswebextension";
2626

2727
import { Network } from "./network";
2828
import { Storage } from "./storage";
2929
import { FiltersApi, FiltersUpdateService, LocaleDetectService } from "./filters";
3030
import { Configuration, configurationValidator } from "./schemas";
31-
import { DetectFiltersEvent, notifier, NotifierEventType } from "./notifier";
31+
import { DeleteFiltersEvent, DetectFiltersEvent, notifier, NotifierEventType } from "./notifier";
3232
import { RequestBlockingLogger } from "./request-blocking-logger";
3333
import { Logger } from "./logger";
3434

@@ -79,6 +79,11 @@ export class AdguardApi {
7979
*/
8080
public onAssistantCreateRule: EventChannel<string>;
8181

82+
/**
83+
* {@link TsWebExtension} {@link EventChannel}, which fires event on obsoleted filters deletion.
84+
*/
85+
public onFiltersDeletion: EventChannel<number[]>;
86+
8287
/**
8388
* API for adding and removing listeners for request blocking events.
8489
*
@@ -91,6 +96,8 @@ export class AdguardApi {
9196

9297
this.onAssistantCreateRule = this.tswebextension.onAssistantCreateRule;
9398

99+
this.onFiltersDeletion = new EventChannel<number[]>();
100+
94101
this.network = new Network();
95102

96103
const storage = new Storage();
@@ -106,6 +113,7 @@ export class AdguardApi {
106113
this.openAssistant = this.openAssistant.bind(this);
107114
this.handleDetectFilters = this.handleDetectFilters.bind(this);
108115
this.handleUpdateFilters = this.handleUpdateFilters.bind(this);
116+
this.handleDeleteFilters = this.handleDeleteFilters.bind(this);
109117
}
110118

111119
/**
@@ -121,25 +129,28 @@ export class AdguardApi {
121129
* Initializes AdGuard with specified {@link Configuration} and starts it immediately.
122130
*
123131
* @param configuration - api {@link Configuration}
124-
* @returns applied {@link Configuration} promise
132+
*
133+
* @returns applied {@link Configuration} promise.
125134
*/
126135
public async start(configuration: Configuration): Promise<Configuration> {
127136
this.configuration = configurationValidator.parse(configuration);
128137

129138
this.network.configure(this.configuration);
130139

131-
await this.filtersApi.init();
140+
const obsoletedFiltersIds = await this.filtersApi.init(configuration.filters);
141+
this.configuration.filters = this.configuration.filters.filter((id) => !obsoletedFiltersIds.includes(id));
132142
this.filtersUpdateService.start();
133143
this.localeDetectService.start();
134144

135145
notifier.addListener(NotifierEventType.UpdateFilters, this.handleUpdateFilters);
136146
notifier.addListener(NotifierEventType.DetectFilters, this.handleDetectFilters);
147+
notifier.addListener(NotifierEventType.DeleteFilters, this.handleDeleteFilters);
137148

138149
const tsWebExtensionConfiguration = await this.createTsWebExtensionConfiguration();
139150

140151
await this.tswebextension.start(tsWebExtensionConfiguration);
141152

142-
return configuration;
153+
return this.configuration;
143154
}
144155

145156
/**
@@ -155,7 +166,8 @@ export class AdguardApi {
155166
* Modifies AdGuard {@link Configuration}. Please note, that Adguard must be already started.
156167
*
157168
* @param configuration - api {@link Configuration}
158-
* @returns applied {@link Configuration} promise
169+
*
170+
* @returns applied {@link Configuration} promise.
159171
*/
160172
public async configure(configuration: Configuration): Promise<Configuration> {
161173
this.configuration = configurationValidator.parse(configuration);
@@ -166,7 +178,7 @@ export class AdguardApi {
166178

167179
await this.tswebextension.configure(tsWebExtensionConfiguration);
168180

169-
return configuration;
181+
return this.configuration;
170182
}
171183

172184
/**
@@ -271,6 +283,23 @@ export class AdguardApi {
271283
this.logger.info("Reload engine with updated filter ids list");
272284
}
273285

286+
/**
287+
* Handles fired {@link DeleteFiltersEvent}
288+
*
289+
* @param event - fired {@link DeleteFiltersEvent}
290+
*/
291+
private async handleDeleteFilters(event: DeleteFiltersEvent): Promise<void> {
292+
const deletedFiltersIds = event.data.filtersIds;
293+
294+
if (deletedFiltersIds.length === 0) {
295+
return;
296+
}
297+
298+
this.onFiltersDeletion.dispatch(deletedFiltersIds);
299+
300+
this.logger.info(`Filters with ids ${deletedFiltersIds} has been removed.`);
301+
}
302+
274303
/**
275304
* Handles fired {@link DetectFiltersEvent}
276305
*

packages/adguard-api/src/background/notifier.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
export enum NotifierEventType {
2020
DetectFilters = "DetectFilters",
2121
UpdateFilters = "UpdateFilters",
22+
DeleteFilters = "DeleteFilters",
2223
}
2324

2425
export type DetectFiltersEvent = {
@@ -32,7 +33,14 @@ export type UpdateFiltersEvent = {
3233
type: NotifierEventType.UpdateFilters;
3334
};
3435

35-
export type NotifierEvent = DetectFiltersEvent | UpdateFiltersEvent;
36+
export type DeleteFiltersEvent = {
37+
type: NotifierEventType.DeleteFilters;
38+
data: {
39+
filtersIds: number[];
40+
};
41+
};
42+
43+
export type NotifierEvent = DetectFiltersEvent | UpdateFiltersEvent | DeleteFiltersEvent;
3644

3745
export type ExtractedNotifierEvent<T> = Extract<NotifierEvent, { type: T }>;
3846

@@ -50,6 +58,7 @@ export class Notifier {
5058
private listenersMap: NotifierListenersMap = {
5159
[NotifierEventType.DetectFilters]: [],
5260
[NotifierEventType.UpdateFilters]: [],
61+
[NotifierEventType.DeleteFilters]: [],
5362
};
5463

5564
/**
@@ -79,7 +88,7 @@ export class Notifier {
7988
*
8089
* @param event - event data
8190
*/
82-
public publishEvent<T extends DetectFiltersEvent | UpdateFiltersEvent>(event: T): void {
91+
public publishEvent<T extends NotifierEvent>(event: T): void {
8392
const listeners = this.listenersMap[event.type] as NotifierListener<NotifierEventType>[];
8493

8594
listeners.forEach((listener) => {

0 commit comments

Comments
 (0)