Project

General

Profile

Download (2.83 KB) Statistics
| Branch: | Tag: | Revision:

haketilo / common / storage_light.js @ 6247f163

1
/**
2
 * part of Hachette
3
 * Storage manager, lighter than the previous one.
4
 *
5
 * Copyright (C) 2021 Wojtek Kosior
6
 * Redistribution terms are gathered in the `copyright' file.
7
 */
8

    
9
/*
10
 * IMPORTS_START
11
 * IMPORT TYPE_PREFIX
12
 * IMPORT raw_storage
13
 * IMPORT is_mozilla
14
 * IMPORT observables
15
 */
16

    
17
const reg_spec = new Set(["\\", "[", "]", "(", ")", "{", "}", ".", "*", "+"]);
18
const escape_reg_special = c => reg_spec.has(c) ? "\\" + c : c;
19

    
20
function make_regex(name)
21
{
22
    return new RegExp(`^${name.split("").map(escape_reg_special).join("")}\$`);
23
}
24

    
25
const listeners_by_callback = new Map();
26

    
27
function listen(callback, prefix, name)
28
{
29
    let by_prefix = listeners_by_callback.get(callback);
30
    if (!by_prefix) {
31
	by_prefix = new Map();
32
	listeners_by_callback.set(callback, by_prefix);
33
    }
34

    
35
    let by_name = by_prefix.get(prefix);
36
    if (!by_name) {
37
	by_name = new Map();
38
	by_prefix.set(prefix, by_name);
39
    }
40

    
41
    let name_reg = by_name.get(name);
42
    if (!name_reg) {
43
	name_reg = name.test ? name : make_regex(name);
44
	by_name.set(name, name_reg);
45
    }
46
}
47

    
48
function no_listen(callback, prefix, name)
49
{
50
    const by_prefix = listeners_by_callback.get(callback);
51
    if (!by_prefix)
52
	return;
53

    
54
    const by_name = by_prefix.get(prefix);
55
    if (!by_name)
56
	return;
57

    
58
    const name_reg = by_name.get(name);
59
    if (!name_reg)
60
	return;
61

    
62
    by_name.delete(name);
63

    
64
    if (by_name.size === 0)
65
	by_prefix.delete(prefix);
66

    
67
    if (by_prefix.size === 0)
68
	listeners_by_callback.delete(callback);
69
}
70

    
71
function storage_change_callback(changes, area)
72
{
73
    if (is_mozilla && area !== "local")
74
    {console.log("area", area);return;}
75

    
76
    for (const item of Object.keys(changes)) {
77
	for (const [callback, by_prefix] of listeners_by_callback.entries()) {
78
	    const by_name = by_prefix.get(item[0]);
79
	    if (!by_name)
80
		continue;
81

    
82
	    for (const reg of by_name.values()) {
83
		if (!reg.test(item.substring(1)))
84
		    continue;
85

    
86
		try {
87
		    callback(item, changes[item]);
88
		} catch(e) {
89
		    console.error(e);
90
		}
91
	    }
92
	}
93
    }
94
}
95

    
96
raw_storage.listen(storage_change_callback);
97

    
98

    
99
const created_observables = new Map();
100

    
101
async function observe(prefix, name)
102
{
103
    const observable = observables.make();
104
    const callback = (it, ch) => observables.set(observable, ch.newValue);
105
    listen(callback, prefix, name);
106
    created_observables.set(observable, [callback, prefix, name]);
107
    observables.silent_set(observable, await raw_storage.get(prefix + name));
108

    
109
    return observable;
110
}
111

    
112
const observe_var = name => observe(TYPE_PREFIX.VAR, name);
113

    
114
function no_observe(observable)
115
{
116
    no_listen(...created_observables.get(observable) || []);
117
    created_observables.delete(observable);
118
}
119

    
120
const light_storage = {};
121
Object.assign(light_storage, raw_storage);
122
Object.assign(light_storage,
123
	      {listen, no_listen, observe, observe_var, no_observe});
124

    
125
/*
126
 * EXPORTS_START
127
 * EXPORT light_storage
128
 * EXPORTS_END
129
 */
(14-14/16)