-
Notifications
You must be signed in to change notification settings - Fork 520
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- todo: mini program and harmony
- Loading branch information
Showing
53 changed files
with
2,211 additions
and
308 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import * as common from '../@internal' | ||
|
||
export class LocalStorageCacheManager<T> implements common.cache.PersistentCacheManager<T> { | ||
persistPath: string; | ||
|
||
constructor(persistLocation: string) { | ||
this.persistPath = persistLocation | ||
} | ||
|
||
async get(key: string): Promise<T | null> { | ||
const itemKey = this.getPersistKey(key) | ||
const raw = localStorage.getItem(itemKey) | ||
if (!raw) { | ||
return null | ||
} | ||
return this.parse(raw) | ||
} | ||
|
||
async set(key: string, val: T): Promise<void> { | ||
const itemKey = this.getPersistKey(key) | ||
const raw = this.stringify(val) | ||
localStorage.setItem(itemKey, raw) | ||
} | ||
|
||
async delete(key: string): Promise<void> { | ||
const itemKey = this.getPersistKey(key) | ||
localStorage.removeItem(itemKey) | ||
} | ||
|
||
private getPersistKey(key: string): string { | ||
return `qnsdk:${this.persistPath}:${key}` | ||
} | ||
|
||
private parse(val: string): T { | ||
return JSON.parse(val) | ||
} | ||
|
||
private stringify(val: T): string { | ||
return JSON.stringify(val) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { MemoryCacheManager, PersistentNever } from './index' | ||
|
||
interface CacheData { | ||
result: string | ||
} | ||
|
||
describe('CacheManager', () => { | ||
test('test MemoryCacheManager', async () => { | ||
const memoryCacheManager = new MemoryCacheManager<CacheData>() | ||
|
||
await memoryCacheManager.set('key', { | ||
result: 'val' | ||
}) | ||
let val = await memoryCacheManager.get('key') | ||
expect(val).toEqual({ | ||
result: 'val' | ||
}) | ||
|
||
await memoryCacheManager.delete('key') | ||
val = await memoryCacheManager.get('key') | ||
expect(val).toBe(null) | ||
}) | ||
|
||
test('test PersistentNever', async () => { | ||
const cacheManager = new PersistentNever<CacheData>() | ||
|
||
await cacheManager.set('key', { | ||
result: 'val' | ||
}) | ||
let val = await cacheManager.get('key') | ||
expect(val).toBe(null) | ||
|
||
await cacheManager.delete('key') | ||
val = await cacheManager.get('key') | ||
expect(val).toBe(null) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
interface CacheManager<T> { | ||
get(key: string): Promise<T | null>; | ||
set(key: string, val: T): Promise<void>; | ||
delete(key: string): Promise<void>; | ||
} | ||
|
||
export interface PersistentCacheManager<T> extends CacheManager<T> { | ||
persistLocation: string | ||
} | ||
|
||
export class MemoryCacheManager<T> implements CacheManager<T> { | ||
private cache: Map<string, T> = new Map() | ||
|
||
async get(key: string): Promise<T | null> { | ||
return this.cache.get(key) ?? null | ||
} | ||
|
||
async set(key: string, val: T): Promise<void> { | ||
this.cache.set(key, val) | ||
} | ||
|
||
async delete(key: string): Promise<void> { | ||
this.cache.delete(key) | ||
} | ||
} | ||
|
||
export class PersistentNever<T = any> implements PersistentCacheManager<T> { | ||
persistLocation: string | ||
|
||
constructor() { | ||
this.persistLocation = '' | ||
} | ||
|
||
async get(key: string): Promise<T | null> { | ||
return null | ||
} | ||
|
||
async set(key: string, val: T): Promise<void> { | ||
// do nothing | ||
} | ||
|
||
async delete(key: string): Promise<void> { | ||
// do nothing | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { MemoryCacheManager, PersistentCacheManager } from './index' | ||
|
||
export class MockCacheManager<T> extends MemoryCacheManager<T> implements PersistentCacheManager<T> { | ||
persistLocation = '' | ||
|
||
get = jest.fn<Promise<T | null>, [string]>(() => Promise.resolve(null)) | ||
set = jest.fn<Promise<void>, [string, T]>(() => Promise.resolve()) | ||
delete = jest.fn<Promise<void>, [string]>(() => Promise.resolve()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { | ||
FixedBackoff, | ||
ExponentialBackoff, | ||
RandomizedBackoff, | ||
LimitedBackoff | ||
} from './backoff' | ||
|
||
describe('retry backoff test', () => { | ||
test('test FixedBackoff', () => { | ||
const backoff = new FixedBackoff(1000) | ||
expect(backoff.getDelay()).toBe(1000) | ||
}) | ||
|
||
test('test ExponentialBackoff', () => { | ||
const backoff = new ExponentialBackoff(1000) | ||
expect(backoff.getDelay()).toBe(1000) | ||
expect(backoff.getDelay()).toBe(2000) | ||
expect(backoff.getDelay()).toBe(4000) | ||
expect(backoff.getDelay()).toBe(8000) | ||
}) | ||
|
||
test('test RandomizedBackoff', () => { | ||
const backoff = new RandomizedBackoff(new FixedBackoff(1000), 100) | ||
for (let i = 0; i < 100; i += 1) { | ||
expect(backoff.getDelay()).toBeGreaterThan(900) | ||
expect(backoff.getDelay()).toBeLessThanOrEqual(1100) | ||
} | ||
|
||
const backoff2 = new RandomizedBackoff(new FixedBackoff(1000), 10000) | ||
for (let i = 0; i < 100; i += 1) { | ||
expect(backoff.getDelay()).toBeGreaterThan(0) | ||
expect(backoff.getDelay()).toBeLessThanOrEqual(11000) | ||
} | ||
}) | ||
|
||
test('test LimitedBackoff', () => { | ||
const backoff = new LimitedBackoff(new ExponentialBackoff(1000), 2000) | ||
expect(backoff.getDelay()).toBe(1000) | ||
expect(backoff.getDelay()).toBe(2000) | ||
expect(backoff.getDelay()).toBe(2000) | ||
expect(backoff.getDelay()).toBe(2000) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
export abstract class Backoff { | ||
abstract getDelay(): number | ||
|
||
async wait() { | ||
const n = this.getDelay() | ||
if (n <= 0) { | ||
return | ||
} | ||
await new Promise(resolve => setTimeout(resolve, n)) | ||
} | ||
} | ||
|
||
export class FixedBackoff extends Backoff { | ||
private delay: number | ||
constructor(delay: number) { | ||
super() | ||
this.delay = delay | ||
} | ||
|
||
getDelay(): number { | ||
return this.delay | ||
} | ||
} | ||
|
||
export class ExponentialBackoff extends Backoff { | ||
private base: number | ||
private factor: number | ||
private next: number | ||
|
||
constructor(base: number, factor = 2) { | ||
super() | ||
this.base = base | ||
this.factor = factor | ||
this.next = base | ||
} | ||
|
||
getDelay(): number { | ||
const delay = this.next | ||
this.next *= this.factor | ||
return delay | ||
} | ||
} | ||
|
||
const Second = 1000 | ||
|
||
// make the backoff delay duration plus the delta, | ||
// delta is belong to (-delta, delta), not inclusive | ||
export class RandomizedBackoff extends Backoff { | ||
private backoff: Backoff | ||
private delta: number // int, in milliseconds | ||
|
||
constructor(backoff: Backoff, delta = 2 * Second) { | ||
super() | ||
this.backoff = backoff | ||
this.delta = Math.floor(delta) | ||
} | ||
|
||
getDelay(): number { | ||
let diff = Math.floor(Math.random() * this.delta) | ||
diff = Math.floor(Math.random() * 2) ? diff : -diff | ||
const delay = this.backoff.getDelay() + diff | ||
return Math.max(0, delay) | ||
} | ||
} | ||
|
||
export class LimitedBackoff extends Backoff { | ||
private backoff: Backoff | ||
private min: number | ||
private max: number | ||
|
||
constructor(backoff: Backoff, max: number, min = 0) { | ||
super() | ||
if (min > max) { | ||
throw new Error('min should be less than or equal to max') | ||
} | ||
this.backoff = backoff | ||
this.max = max | ||
this.min = min | ||
} | ||
|
||
getDelay(): number { | ||
let delay = Math.min( | ||
this.max, | ||
this.backoff.getDelay() | ||
) | ||
delay = Math.max( | ||
this.min, | ||
delay | ||
) | ||
return delay | ||
} | ||
} | ||
|
||
export function getDefaultBackoff(): Backoff { | ||
const exponential = new ExponentialBackoff(3 * Second) | ||
const randomized = new RandomizedBackoff(exponential, Second) | ||
return new LimitedBackoff(randomized, 30 * Second) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './types' | ||
export * from './backoff' | ||
export * from './retrier' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
describe('retry backoff test', () => { | ||
test('test retrier', () => { | ||
expect(1).toBe(1) | ||
}) | ||
}) |
Oops, something went wrong.