123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- import { arrayToB64, isFile } from './utils';
- import OwnedFile from './ownedFile';
- class Mem {
- constructor() {
- this.items = new Map();
- }
- get length() {
- return this.items.size;
- }
- getItem(key) {
- return this.items.get(key);
- }
- setItem(key, value) {
- return this.items.set(key, value);
- }
- removeItem(key) {
- return this.items.delete(key);
- }
- key(i) {
- return this.items.keys()[i];
- }
- }
- class Storage {
- constructor() {
- try {
- this.engine = localStorage || new Mem();
- } catch (e) {
- this.engine = new Mem();
- }
- this._files = this.loadFiles();
- this.pruneTokens();
- }
- loadFiles() {
- const fs = new Map();
- for (let i = 0; i < this.engine.length; i++) {
- const k = this.engine.key(i);
- if (isFile(k)) {
- try {
- const f = new OwnedFile(JSON.parse(this.engine.getItem(k)));
- if (!f.id) {
- f.id = f.fileId;
- }
- fs.set(f.id, f);
- } catch (err) {
- // obviously you're not a golfer
- this.engine.removeItem(k);
- }
- }
- }
- return fs;
- }
- get id() {
- let id = this.engine.getItem('device_id');
- if (!id) {
- id = arrayToB64(crypto.getRandomValues(new Uint8Array(16)));
- this.engine.setItem('device_id', id);
- }
- return id;
- }
- get totalDownloads() {
- return Number(this.engine.getItem('totalDownloads'));
- }
- set totalDownloads(n) {
- this.engine.setItem('totalDownloads', n);
- }
- get totalUploads() {
- return Number(this.engine.getItem('totalUploads'));
- }
- set totalUploads(n) {
- this.engine.setItem('totalUploads', n);
- }
- get referrer() {
- return this.engine.getItem('referrer');
- }
- set referrer(str) {
- this.engine.setItem('referrer', str);
- }
- get enrolled() {
- return JSON.parse(this.engine.getItem('ab_experiments') || '{}');
- }
- enroll(id, variant) {
- const enrolled = {};
- enrolled[id] = variant;
- this.engine.setItem('ab_experiments', JSON.stringify(enrolled));
- }
- get files() {
- return Array.from(this._files.values()).sort(
- (a, b) => a.createdAt - b.createdAt
- );
- }
- get user() {
- try {
- return JSON.parse(this.engine.getItem('user'));
- } catch (e) {
- return null;
- }
- }
- set user(info) {
- return this.engine.setItem('user', JSON.stringify(info));
- }
- getFileById(id) {
- return this._files.get(id);
- }
- get(id) {
- return this.engine.getItem(id);
- }
- set(id, value) {
- return this.engine.setItem(id, value);
- }
- remove(property) {
- if (isFile(property)) {
- this._files.delete(property);
- }
- this.engine.removeItem(property);
- }
- addFile(file) {
- this._files.set(file.id, file);
- this.writeFile(file);
- }
- writeFile(file) {
- this.engine.setItem(file.id, JSON.stringify(file));
- }
- writeFiles() {
- this._files.forEach(f => this.writeFile(f));
- }
- clearLocalFiles() {
- this._files.forEach(f => this.engine.removeItem(f.id));
- this._files = new Map();
- }
- async merge(files = []) {
- let incoming = false;
- let outgoing = false;
- let downloadCount = false;
- for (const f of files) {
- if (!this.getFileById(f.id)) {
- this.addFile(new OwnedFile(f));
- incoming = true;
- }
- }
- const workingFiles = this.files.slice();
- for (const f of workingFiles) {
- const cc = await f.updateDownloadCount();
- if (cc) {
- await this.writeFile(f);
- }
- downloadCount = downloadCount || cc;
- outgoing = outgoing || f.expired;
- if (f.expired) {
- this.remove(f.id);
- } else if (!files.find(x => x.id === f.id)) {
- outgoing = true;
- }
- }
- return {
- incoming,
- outgoing,
- downloadCount
- };
- }
- setDownloadToken(id, token) {
- let otherTokens = {};
- try {
- otherTokens = JSON.parse(this.get('dlTokens'));
- } catch (e) {
- //
- }
- if (token) {
- const record = { token, ts: Date.now() };
- this.set('dlTokens', JSON.stringify({ ...otherTokens, [id]: record }));
- } else {
- this.set('dlTokens', JSON.stringify({ ...otherTokens, [id]: undefined }));
- }
- }
- getDownloadToken(id) {
- try {
- return JSON.parse(this.get('dlTokens'))[id].token;
- } catch (e) {
- return undefined;
- }
- }
- pruneTokens() {
- try {
- const now = Date.now();
- const tokens = JSON.parse(this.get('dlTokens'));
- const keep = {};
- for (const id of Object.keys(tokens)) {
- const t = tokens[id];
- if (t.ts > now - 7 * 86400 * 1000) {
- keep[id] = t;
- }
- }
- if (Object.keys(keep).length < Object.keys(tokens).length) {
- this.set('dlTokens', JSON.stringify(keep));
- }
- } catch (e) {
- console.error(e);
- }
- }
- }
- export default new Storage();
|