Skip to content

Commit

Permalink
Feat: Plugin storages (LNReader#986)
Browse files Browse the repository at this point in the history
* test

* fix

* Update pluginManager.ts

* test

* fix lint

* test

* test webview

* sync

* /

* Update WebviewScreen.tsx

* CookieManager

* Update storage.ts

* Update сookie.ts

* fix title

* MarqueeText...

* Slow

* Even slower

* Squashed commit of the following:

commit da4d7e8
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Fri Mar 8 13:21:19 2024 +0300

    /

commit 592c4db
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Fri Mar 8 13:20:34 2024 +0300

    test

commit 6324050
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Fri Mar 8 12:38:13 2024 +0300

    /

commit 591d259
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Fri Mar 8 11:42:03 2024 +0300

    fix progressbar

commit 3d34cfb
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 21:13:49 2024 +0300

    forgot

commit c36d090
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 20:51:31 2024 +0300

    /

commit 3c4e43b
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 20:15:38 2024 +0300

    /

commit 0a20a48
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 19:46:31 2024 +0300

    add zIndex

commit 7d44901
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 19:27:32 2024 +0300

    test

commit b585d5e
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 18:28:49 2024 +0300

    /

commit cb7241c
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 18:06:30 2024 +0300

    Update Appbar.tsx

commit 5fab766
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 17:55:24 2024 +0300

    Update WebviewScreen.tsx

commit aec9b92
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 17:15:16 2024 +0300

    xd

commit 1fa385b
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 17:11:23 2024 +0300

    2

commit 589870d
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 16:28:24 2024 +0300

    1

commit 343d2dd
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 16:11:08 2024 +0300

    test

commit f2dbf34
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Thu Mar 7 14:36:48 2024 +0300

    test

commit 04c04d9
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Wed Mar 6 22:37:45 2024 +0300

    test zoom

commit 6b80559
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Wed Mar 6 22:33:55 2024 +0300

    fix

commit 287ce94
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Wed Mar 6 19:00:01 2024 +0300

    test

commit 67bdddc
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Wed Mar 6 11:10:22 2024 +0300

    Test newArch

commit 7623537
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Tue Mar 5 20:49:29 2024 +0300

    Update Appbar.tsx

commit 2a876cb
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Tue Mar 5 20:42:28 2024 +0300

    modal

commit ba4cade
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Tue Mar 5 16:50:38 2024 +0300

    1

commit 6c14a18
Author: Rider21 <58046032+Rider21@users.noreply.github.com>
Date:   Tue Mar 5 14:54:27 2024 +0300

    test

* fix

* fix

* Update pluginManager.ts

* test

* fix

* fix lint

* -marquee

* fix defaultCover

* test

* Update src/plugins/helpers/storage.ts

Co-authored-by: nyagami <hoangquan05112002@gmail.com>

* test

* Typescript fixes

* private pluginID

---------

Co-authored-by: nyagami <hoangquan05112002@gmail.com>
  • Loading branch information
Rider21 and nyagami authored May 28, 2024
1 parent 1ac6d11 commit e50b6c4
Show file tree
Hide file tree
Showing 18 changed files with 401 additions and 145 deletions.
20 changes: 6 additions & 14 deletions package-lock.json

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

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"i18n-js": "^3.8.0",
"lodash-es": "^4.17.21",
"protobufjs": "^7.2.6",
"qs": "^6.11.2",
"qs": "^6.12.0",
"react": "18.2.0",
"react-native": "0.72.10",
"react-native-background-actions": "^3.0.1",
Expand All @@ -62,7 +62,7 @@
"react-native-tab-view": "^3.5.2",
"react-native-vector-icons": "^9.0.0",
"react-native-webview": "^13.2.2",
"sanitize-html": "^2.7.0",
"sanitize-html": "^2.13.0",
"urlencode": "^2.0.0"
},
"devDependencies": {
Expand All @@ -76,7 +76,7 @@
"@types/lodash-es": "^4.17.6",
"@types/react": "^18.0.24",
"@types/react-native-vector-icons": "^6.4.10",
"@types/sanitize-html": "^2.6.2",
"@types/sanitize-html": "^2.11.0",
"@typescript-eslint/eslint-plugin": "^5.10.2",
"@typescript-eslint/parser": "^5.10.2",
"babel-plugin-module-resolver": "^4.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/persisted/usePlugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export default function usePlugins() {
*/

const installPlugin = (plugin: PluginItem) => {
return _install(plugin.url).then(_plg => {
return _install(plugin.id, plugin.url).then(_plg => {
if (_plg) {
const installedPlugins =
getMMKVObject<PluginItem[]>(INSTALLED_PLUGINS) || [];
Expand Down
2 changes: 1 addition & 1 deletion src/navigators/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export type RootStackParamList = {
WebviewScreen: {
name: string;
url: string;
pluginId?: string;
pluginId: string;
isNovel?: boolean;
};
};
Expand Down
2 changes: 0 additions & 2 deletions src/plugins/helpers/constants.js

This file was deleted.

2 changes: 2 additions & 0 deletions src/plugins/helpers/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const defaultCover =
'https://github.com/LNReader/lnreader-plugins/blob/master/icons/coverNotAvailable.webp?raw=true';
123 changes: 123 additions & 0 deletions src/plugins/helpers/storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { MMKV } from 'react-native-mmkv';

const store = new MMKV({ id: 'plugin_db' });

const PLUGIN_STORAGE = '_DB_';
const WEBVIEW_LOCAL_STORAGE = '_LocalStorage';
const WEBVIEW_SESSION_STORAGE = '_SessionStorage';

interface StoredItem {
created: Date;
value: any;
expires?: number; // timestamp (miliseconds)
}

class Storage {
#pluginID: string;

constructor(pluginID: string) {
this.#pluginID = pluginID;
}

/**
* Sets a key-value pair in storage.
*
* @param {string} key - The key to set.
* @param {any} value - The value to set.
* @param {Date | number} [expires] - Optional expiry date or time in milliseconds.
*/
set(key: string, value: any, expires?: Date | number): void {
const item: StoredItem = {
created: new Date(),
value,
expires: expires instanceof Date ? expires.getTime() : expires,
};
store.set(this.#pluginID + PLUGIN_STORAGE + key, JSON.stringify(item));
}

/**
* Retrieves the value for a given key from storage.
*
* @param {string} key - The key to retrieve the value for.
* @param {boolean} [raw] - Optional flag to return the raw stored item.
* @returns {any} The stored value or undefined if key is not found.
*/
get(key: string, raw?: boolean): any {
const storedItem = store.getString(this.#pluginID + PLUGIN_STORAGE + key);
if (storedItem) {
const item: StoredItem = JSON.parse(storedItem);
if (item.expires) {
if (Date.now() > item.expires) {
this.delete(key);
return undefined;
}
if (raw) {
item.expires = new Date(item.expires).getTime();
}
}
return raw ? item : item.value;
}
return undefined;
}

/**
* Deletes a key from storage.
*
* @param {string} key - The key to delete.
*/
delete(key: string): void {
store.delete(this.#pluginID + PLUGIN_STORAGE + key);
}

/**
* Clears all stored items from storage.
*/
clearAll(): void {
const keysToRemove = this.getAllKeys();
keysToRemove.forEach(key => this.delete(key));
}

/**
* Retrieves all keys set by the `set` method.
*
* @returns {string[]} An array of keys.
*/
getAllKeys(): string[] {
const keys = store
.getAllKeys()
.filter(key => key.startsWith(this.#pluginID + PLUGIN_STORAGE))
.map(key => key.replace(this.#pluginID + PLUGIN_STORAGE, ''));
return keys;
}
}

class LocalStorage {
#pluginID: string;

constructor(pluginID: string) {
this.#pluginID = pluginID;
}

get(): StoredItem['value'] | undefined {
const data = store.getString(this.#pluginID + WEBVIEW_LOCAL_STORAGE);
return data ? JSON.parse(data) : undefined;
}
}

class SessionStorage {
#pluginID: string;

constructor(pluginID: string) {
this.#pluginID = pluginID;
}

get(): StoredItem['value'] | undefined {
const data = store.getString(this.#pluginID + WEBVIEW_SESSION_STORAGE);
return data ? JSON.parse(data) : undefined;
}
}

export { Storage, LocalStorage, SessionStorage };

//to record data from the web view
export { WEBVIEW_LOCAL_STORAGE, WEBVIEW_SESSION_STORAGE, store };
44 changes: 31 additions & 13 deletions src/plugins/pluginManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import RNFS from 'react-native-fs';
import { reverse, uniqBy } from 'lodash-es';
import { PluginDownloadFolder } from '@utils/constants/download';
import { newer } from '@utils/compareVersion';
import { store } from './helpers/storage';

// packages for plugins
import { load } from 'cheerio';
Expand All @@ -12,6 +13,7 @@ import { FilterTypes } from './types/filterTypes';
import { isUrlAbsolute } from './helpers/isAbsoluteUrl';
import { fetchApi, fetchFile, fetchProto, fetchText } from './helpers/fetch';
import { defaultCover } from './helpers/constants';
import { Storage, LocalStorage, SessionStorage } from './helpers/storage';
import { encode, decode } from 'urlencode';
import { Parser } from 'htmlparser2';
import TextFile from '@native/TextFile';
Expand All @@ -33,12 +35,18 @@ const packages: Record<string, any> = {
'@libs/defaultCover': { defaultCover },
};

const _require = (packageName: string) => {
return packages[packageName];
};

const initPlugin = (rawCode: string) => {
const initPlugin = (pluginId: string, rawCode: string) => {
try {
const _require = (packageName: string) => {
if (packageName === '@libs/storage') {
return {
storage: new Storage(pluginId),
localStorage: new LocalStorage(pluginId),
sessionStorage: new SessionStorage(pluginId),
};
}
return packages[packageName];
};
/* eslint no-new-func: "off", curly: "error" */
const plugin: Plugin = Function(
'require',
Expand Down Expand Up @@ -84,26 +92,31 @@ const deserializePlugins = () => {
return TextFile.readFile(pluginsFilePath)
.then(content => {
serializedPlugins = JSON.parse(content);
for (const script of Object.values(serializedPlugins)) {
const plugin = initPlugin(script as string);
if (plugin) {
plugins[plugin.id] = plugin;
Object.entries(serializedPlugins).forEach(([pluginId, script]) => {
if (script) {
const plugin = initPlugin(pluginId, script);
if (plugin) {
plugins[plugin.id] = plugin;
}
}
}
});
})
.catch(() => {
// nothing to read
});
};

const installPlugin = async (url: string): Promise<Plugin | undefined> => {
const installPlugin = async (
pluginId: string,
url: string,
): Promise<Plugin | undefined> => {
try {
return await fetch(url, {
headers: { 'pragma': 'no-cache', 'cache-control': 'no-cache' },
})
.then(res => res.text())
.then(async rawCode => {
const plugin = initPlugin(rawCode);
const plugin = initPlugin(pluginId, rawCode);
if (!plugin) {
return undefined;
}
Expand All @@ -122,11 +135,16 @@ const installPlugin = async (url: string): Promise<Plugin | undefined> => {

const uninstallPlugin = async (_plugin: PluginItem) => {
plugins[_plugin.id] = undefined;
store.getAllKeys().forEach(key => {
if (key.startsWith(_plugin.id)) {
store.delete(key);
}
});
return serializePlugin(_plugin.id, '', false);
};

const updatePlugin = async (plugin: PluginItem) => {
return installPlugin(plugin.url);
return installPlugin(plugin.id, plugin.url);
};

const fetchPlugins = async (): Promise<PluginItem[]> => {
Expand Down
14 changes: 7 additions & 7 deletions src/plugins/types/filterTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ type ExcludableCheckboxFilter = {

export type Filters = Record<
string,
| { label: string } & (
| PickerFilter
| CheckboxFilter
| TextFilter
| SwitchFilter
| ExcludableCheckboxFilter
)
{ label: string } & (
| PickerFilter
| CheckboxFilter
| TextFilter
| SwitchFilter
| ExcludableCheckboxFilter
)
>;

export type FilterToValues<
Expand Down
1 change: 1 addition & 0 deletions src/plugins/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,5 @@ export interface Plugin extends PluginItem {
searchNovels: (searchTerm: string, pageNo: number) => Promise<NovelItem[]>;
fetchImage: (url: string) => Promise<string>;
resolveUrl?: (path: string, isNovel?: boolean) => string;
webStorageUtilized?: boolean;
}
1 change: 1 addition & 0 deletions src/screens/BrowseSourceScreen/BrowseSourceScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const BrowseSourceScreen = ({ route, navigation }: BrowseSourceScreenProps) => {
navigation.navigate('WebviewScreen', {
name: pluginName,
url: site,
pluginId,
});
};

Expand Down
Loading

0 comments on commit e50b6c4

Please sign in to comment.