mirror of
https://github.com/laurent22/joplin.git
synced 2024-11-27 08:21:03 +02:00
Removed cache package dependency and implemented one more suitable for React Native
This commit is contained in:
parent
efa346fea4
commit
eec32cf70a
@ -64,6 +64,7 @@ CliClient/build/
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
CliClient/app/LinkSelector.js
|
||||
CliClient/app/services/plugins/PluginRunner.js
|
||||
CliClient/tests/InMemoryCache.js
|
||||
CliClient/tests/models_Setting.js
|
||||
CliClient/tests/services_CommandService.js
|
||||
CliClient/tests/services_InteropService.js
|
||||
@ -210,6 +211,7 @@ ReactNativeClient/lib/hooks/useEffectDebugger.js
|
||||
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
|
||||
ReactNativeClient/lib/hooks/usePrevious.js
|
||||
ReactNativeClient/lib/hooks/usePropsDebugger.js
|
||||
ReactNativeClient/lib/InMemoryCache.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/checkbox.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/fence.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/mermaid.js
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -58,6 +58,7 @@ plugin_types/
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
CliClient/app/LinkSelector.js
|
||||
CliClient/app/services/plugins/PluginRunner.js
|
||||
CliClient/tests/InMemoryCache.js
|
||||
CliClient/tests/models_Setting.js
|
||||
CliClient/tests/services_CommandService.js
|
||||
CliClient/tests/services_InteropService.js
|
||||
@ -204,6 +205,7 @@ ReactNativeClient/lib/hooks/useEffectDebugger.js
|
||||
ReactNativeClient/lib/hooks/useImperativeHandlerDebugger.js
|
||||
ReactNativeClient/lib/hooks/usePrevious.js
|
||||
ReactNativeClient/lib/hooks/usePropsDebugger.js
|
||||
ReactNativeClient/lib/InMemoryCache.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/checkbox.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/fence.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/mermaid.js
|
||||
|
5
CliClient/package-lock.json
generated
5
CliClient/package-lock.json
generated
@ -4199,11 +4199,6 @@
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
|
||||
},
|
||||
"memory-cache": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
|
||||
"integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo="
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
|
||||
|
@ -80,7 +80,6 @@
|
||||
"markdown-it-toc-done-right": "^4.1.0",
|
||||
"md5": "^2.2.1",
|
||||
"md5-file": "^4.0.0",
|
||||
"memory-cache": "^0.2.0",
|
||||
"mime": "^2.0.3",
|
||||
"moment": "^2.24.0",
|
||||
"multiparty": "^4.2.1",
|
||||
|
59
CliClient/tests/InMemoryCache.ts
Normal file
59
CliClient/tests/InMemoryCache.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import InMemoryCache from 'lib/InMemoryCache';
|
||||
const { time } = require('lib/time-utils.js');
|
||||
|
||||
describe('InMemoryCache', function() {
|
||||
|
||||
it('should get and set values', () => {
|
||||
const cache = new InMemoryCache();
|
||||
|
||||
expect(cache.value('test')).toBe(undefined);
|
||||
expect(cache.value('test', 'default')).toBe('default');
|
||||
|
||||
cache.setValue('test', 'something');
|
||||
expect(cache.value('test')).toBe('something');
|
||||
|
||||
// Check we get the exact same object back (cache should not copy)
|
||||
const someObj = { abcd: '123' };
|
||||
cache.setValue('someObj', someObj);
|
||||
expect(cache.value('someObj')).toBe(someObj);
|
||||
});
|
||||
|
||||
it('should expire values', async () => {
|
||||
const cache = new InMemoryCache();
|
||||
|
||||
// Check that the value is udefined once the cache has expired
|
||||
cache.setValue('test', 'something', 500);
|
||||
expect(cache.value('test')).toBe('something');
|
||||
await time.msleep(510);
|
||||
expect(cache.value('test')).toBe(undefined);
|
||||
|
||||
// Check that the TTL is reset every time setValue is called
|
||||
cache.setValue('test', 'something', 300);
|
||||
await time.msleep(100);
|
||||
cache.setValue('test', 'something', 300);
|
||||
await time.msleep(100);
|
||||
cache.setValue('test', 'something', 300);
|
||||
await time.msleep(100);
|
||||
cache.setValue('test', 'something', 300);
|
||||
await time.msleep(100);
|
||||
|
||||
expect(cache.value('test')).toBe('something');
|
||||
});
|
||||
|
||||
it('should delete old records', async () => {
|
||||
const cache = new InMemoryCache(5);
|
||||
|
||||
cache.setValue('1', '1');
|
||||
cache.setValue('2', '2');
|
||||
cache.setValue('3', '3');
|
||||
cache.setValue('4', '4');
|
||||
cache.setValue('5', '5');
|
||||
|
||||
expect(cache.value('1')).toBe('1');
|
||||
|
||||
cache.setValue('6', '6');
|
||||
|
||||
expect(cache.value('1')).toBe(undefined);
|
||||
});
|
||||
|
||||
});
|
5
ElectronClient/package-lock.json
generated
5
ElectronClient/package-lock.json
generated
@ -8072,11 +8072,6 @@
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.0.4.tgz",
|
||||
"integrity": "sha512-P0z5IeAH6qHHGkJIXWw0xC2HNEgkx/9uWWBQw64FJj3/ol14VYdfVGWWr0fXfjhhv3TKVIqUq65os6O4GUNksA=="
|
||||
},
|
||||
"memory-cache": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
|
||||
"integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo="
|
||||
},
|
||||
"mermaid": {
|
||||
"version": "8.8.1",
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.8.1.tgz",
|
||||
|
@ -169,7 +169,6 @@
|
||||
"markdown-it-toc-done-right": "^4.1.0",
|
||||
"md5": "^2.2.1",
|
||||
"md5-file": "^4.0.0",
|
||||
"memory-cache": "^0.2.0",
|
||||
"mermaid": "^8.8.1",
|
||||
"moment": "^2.22.2",
|
||||
"multiparty": "^4.2.1",
|
||||
|
84
ReactNativeClient/lib/InMemoryCache.ts
Normal file
84
ReactNativeClient/lib/InMemoryCache.ts
Normal file
@ -0,0 +1,84 @@
|
||||
// There are plenty of packages for in-memory caching but each have their
|
||||
// own gotchas and often have extra complexity which makes it work in one
|
||||
// platform but not in another (for example, the use of long timeouts would
|
||||
// be fine in Node but not in React Native).
|
||||
//
|
||||
// So this class implements a simple in-memory cache with support for TTL.
|
||||
// Checking for expired keys is a bit inefficient since it doesn't rely on
|
||||
// timers, so it's checking every time a value is set or retrieved. But it
|
||||
// should be fine in most cases, as long as the class is not used at a massive
|
||||
// scale.
|
||||
|
||||
interface Record {
|
||||
value: any,
|
||||
expiredTime: number,
|
||||
}
|
||||
|
||||
interface Records {
|
||||
[key:string]: Record;
|
||||
}
|
||||
|
||||
interface ExpirableKeys {
|
||||
[key:string]: boolean,
|
||||
}
|
||||
|
||||
export default class Cache {
|
||||
|
||||
private maxRecords_:number;
|
||||
private records_:Records = {};
|
||||
private expirableKeys_:ExpirableKeys = {};
|
||||
private recordKeyHistory_:string[] = [];
|
||||
|
||||
constructor(maxRecords:number = 50) {
|
||||
this.maxRecords_ = maxRecords;
|
||||
}
|
||||
|
||||
private checkExpiredRecords() {
|
||||
const now = Date.now();
|
||||
|
||||
for (let key in this.expirableKeys_) {
|
||||
if (!this.records_[key]) {
|
||||
delete this.expirableKeys_[key];
|
||||
} else {
|
||||
if (this.records_[key].expiredTime <= now) {
|
||||
delete this.records_[key];
|
||||
delete this.expirableKeys_[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (this.recordKeyHistory_.length > this.maxRecords_) {
|
||||
const key = this.recordKeyHistory_[0];
|
||||
delete this.records_[key];
|
||||
delete this.expirableKeys_[key];
|
||||
this.recordKeyHistory_.splice(0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public value(key:string, defaultValue:any = undefined):any {
|
||||
this.checkExpiredRecords();
|
||||
if (key in this.records_) return this.records_[key].value;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public setValue(key:string, value:any, ttl:number = 0) {
|
||||
this.checkExpiredRecords();
|
||||
|
||||
this.records_[key] = {
|
||||
value: value,
|
||||
expiredTime: ttl ? Date.now() + ttl : 0,
|
||||
}
|
||||
|
||||
const idx = this.recordKeyHistory_.indexOf(key);
|
||||
if (idx >= 0) this.recordKeyHistory_.splice(idx, 1);
|
||||
this.recordKeyHistory_.push(key);
|
||||
|
||||
if (ttl) {
|
||||
this.expirableKeys_[key] = true;
|
||||
} else {
|
||||
delete this.expirableKeys_[key];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { RNCamera } from 'react-native-camera';
|
||||
const { RNCamera } = require('react-native-camera');
|
||||
const React = require('react');
|
||||
const Component = React.Component;
|
||||
const { connect } = require('react-redux');
|
||||
@ -178,7 +178,7 @@ class CameraView extends Component {
|
||||
<View style={{ position: 'absolute', backgroundColor: '#000000', width: '100%', height: '100%' }}/>
|
||||
<RNCamera
|
||||
style={Object.assign({ position: 'absolute' }, cameraRect)}
|
||||
ref={ref => {
|
||||
ref={(ref:any) => {
|
||||
this.camera = ref;
|
||||
}}
|
||||
type={this.props.cameraType}
|
||||
|
@ -3,15 +3,20 @@ const utils = require('./utils');
|
||||
const noteStyle = require('./noteStyle');
|
||||
const Setting = require('lib/models/Setting').default;
|
||||
const { themeStyle } = require('lib/theme');
|
||||
const memoryCache = require('memory-cache');
|
||||
const InMemoryCache = require('lib/InMemoryCache').default;
|
||||
const md5 = require('md5');
|
||||
|
||||
// Renderered notes can potentially be quite large (for example
|
||||
// when they come from the clipper) so keep the cache size
|
||||
// relatively small.
|
||||
const inMemoryCache = new InMemoryCache(10);
|
||||
|
||||
class HtmlToHtml {
|
||||
constructor(options) {
|
||||
if (!options) options = {};
|
||||
this.resourceBaseUrl_ = 'resourceBaseUrl' in options ? options.resourceBaseUrl : null;
|
||||
this.ResourceModel_ = options.ResourceModel;
|
||||
this.cache_ = new memoryCache.Cache();
|
||||
this.cache_ = inMemoryCache;
|
||||
this.fsDriver_ = {
|
||||
writeFile: (/* path, content, encoding = 'base64'*/) => { throw new Error('writeFile not set'); },
|
||||
exists: (/* path*/) => { throw new Error('exists not set'); },
|
||||
@ -55,7 +60,7 @@ class HtmlToHtml {
|
||||
}, options);
|
||||
|
||||
const cacheKey = md5(escape(markup));
|
||||
let html = this.cache_.get(cacheKey);
|
||||
let html = this.cache_.value(cacheKey);
|
||||
|
||||
if (!html) {
|
||||
html = htmlUtils.sanitizeHtml(markup);
|
||||
@ -80,7 +85,7 @@ class HtmlToHtml {
|
||||
});
|
||||
}
|
||||
|
||||
this.cache_.put(cacheKey, html, 1000 * 60 * 10);
|
||||
this.cache_.setValue(cacheKey, html, 1000 * 60 * 10);
|
||||
|
||||
if (options.bodyOnly) {
|
||||
return {
|
||||
|
@ -2,7 +2,7 @@ const MarkdownIt = require('markdown-it');
|
||||
const md5 = require('md5');
|
||||
const noteStyle = require('./noteStyle');
|
||||
const { fileExtension } = require('./pathUtils');
|
||||
const memoryCache = require('memory-cache');
|
||||
const InMemoryCache = require('lib/InMemoryCache').default;
|
||||
|
||||
// /!\/!\ Note: the order of rules is important!! /!\/!\
|
||||
const rules = {
|
||||
@ -44,6 +44,9 @@ function slugify(s) {
|
||||
return nodeSlug(s);
|
||||
}
|
||||
|
||||
// Share across all instances of MdToHtml
|
||||
const inMemoryCache = new InMemoryCache(20);
|
||||
|
||||
class MdToHtml {
|
||||
constructor(options = null) {
|
||||
if (!options) options = {};
|
||||
@ -57,7 +60,7 @@ class MdToHtml {
|
||||
this.cachedHighlightedCode_ = {};
|
||||
this.ResourceModel_ = options.ResourceModel;
|
||||
this.pluginOptions_ = options.pluginOptions ? options.pluginOptions : {};
|
||||
this.contextCache_ = new memoryCache.Cache();
|
||||
this.contextCache_ = inMemoryCache;
|
||||
|
||||
this.tempDir_ = options.tempDir;
|
||||
this.fsDriver_ = {
|
||||
|
@ -16,7 +16,7 @@ function installRule(markdownIt:any, mdOptions:any, ruleOptions:any, context:any
|
||||
}
|
||||
|
||||
const cacheKey = md5(escape(token.content));
|
||||
let sanitizedContent = context.cache.get(cacheKey);
|
||||
let sanitizedContent = context.cache.value(cacheKey);
|
||||
|
||||
// For html_inline, the content is only a fragment of HTML, as it will be rendered, but
|
||||
// it's not necessarily valid HTML. For example this HTML:
|
||||
@ -37,7 +37,7 @@ function installRule(markdownIt:any, mdOptions:any, ruleOptions:any, context:any
|
||||
|
||||
token.content = sanitizedContent;
|
||||
|
||||
context.cache.put(cacheKey, sanitizedContent, 1000 * 60 * 60);
|
||||
context.cache.setValue(cacheKey, sanitizedContent, 1000 * 60 * 60);
|
||||
walkHtmlTokens(token.children);
|
||||
}
|
||||
};
|
||||
|
@ -855,11 +855,6 @@
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
|
||||
},
|
||||
"memory-cache": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
|
||||
"integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo="
|
||||
},
|
||||
"mermaid": {
|
||||
"version": "8.8.1",
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.8.1.tgz",
|
||||
@ -972,9 +967,9 @@
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"slug": {
|
||||
"version": "3.3.5",
|
||||
"resolved": "https://registry.npmjs.org/slug/-/slug-3.3.5.tgz",
|
||||
"integrity": "sha512-d/9yTbJDtSIhJThaNRP/U5uxwCl0mWIlV42JmKSfvg8t7DiVt69G8rAWTc0FWhaQOier0fiNAWVs7ctvVhK1RA=="
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/slug/-/slug-3.5.1.tgz",
|
||||
"integrity": "sha512-ei0JnJzg8HKhLunZy+vpNlILRRradfaAQ+p2YEI4b4r8yX/5TlFi1JSwcYQCg7INZxdTC43BT68rHMkRxzn7Xg=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
|
@ -36,7 +36,6 @@
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-toc-done-right": "^4.1.0",
|
||||
"md5": "^2.2.1",
|
||||
"memory-cache": "^0.2.0",
|
||||
"mermaid": "^8.8.1",
|
||||
"slug": "^3.5.0"
|
||||
}
|
||||
|
5
ReactNativeClient/package-lock.json
generated
5
ReactNativeClient/package-lock.json
generated
@ -7930,11 +7930,6 @@
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
|
||||
},
|
||||
"memory-cache": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
|
||||
"integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo="
|
||||
},
|
||||
"merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
|
@ -46,7 +46,6 @@
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-toc-done-right": "^4.1.0",
|
||||
"md5": "^2.2.1",
|
||||
"memory-cache": "^0.2.0",
|
||||
"mermaid": "^8.8.1",
|
||||
"moment": "^2.24.0",
|
||||
"nanoid": "^3.1.12",
|
||||
|
@ -11,11 +11,10 @@ module.exports = {
|
||||
'**/.git/**',
|
||||
'**/ElectronClient/lib/**',
|
||||
'**/CliClient/build/**',
|
||||
'**/CliClient/tests-build/lib/**',
|
||||
'**/CliClient/tests-build/**',
|
||||
'**/ElectronClient/dist/**',
|
||||
'**/Modules/TinyMCE/JoplinLists/**',
|
||||
'**/Modules/TinyMCE/IconPack/**',
|
||||
'**/CliClient/tests-build/support/**',
|
||||
'**/CliClient/tests/support/plugins/**',
|
||||
'**/plugin_types/**',
|
||||
],
|
||||
|
@ -704,7 +704,9 @@
|
||||
"ReactNativeClient/lib/components/SelectDateTimeDialog.js": true,
|
||||
"ReactNativeClient/lib/PoorManIntervals.js": true,
|
||||
"ReactNativeClient/lib/components/CameraView.js": true,
|
||||
"ReactNativeClient/lib/components/NoteBodyViewer.js": true
|
||||
"ReactNativeClient/lib/components/NoteBodyViewer.js": true,
|
||||
"CliClient/tests/InMemoryCache.js": true,
|
||||
"ReactNativeClient/lib/InMemoryCache.js": true
|
||||
},
|
||||
"spellright.language": [
|
||||
"en"
|
||||
|
Loading…
Reference in New Issue
Block a user