Project

General

Profile

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

haketilo / common / storage_light.js @ 6106c789

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

    
10
/*
11
 * IMPORTS_START
12
 * IMPORT TYPE_PREFIX
13
 * IMPORT raw_storage
14
 * IMPORT is_mozilla
15
 * IMPORT observables
16
 * IMPORTS_END
17
 */
18

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

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

    
27
const listeners_by_callback = new Map();
28

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

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

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

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

    
56
    const by_name = by_prefix.get(prefix);
57
    if (!by_name)
58
	return;
59

    
60
    const name_reg = by_name.get(name);
61
    if (!name_reg)
62
	return;
63

    
64
    by_name.delete(name);
65

    
66
    if (by_name.size === 0)
67
	by_prefix.delete(prefix);
68

    
69
    if (by_prefix.size === 0)
70
	listeners_by_callback.delete(callback);
71
}
72

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

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

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

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

    
98
raw_storage.listen(storage_change_callback);
99

    
100

    
101
const created_observables = new Map();
102

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

    
111
    return observable;
112
}
113

    
114
const observe_var = name => observe(TYPE_PREFIX.VAR, name);
115

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

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

    
127
/*
128
 * EXPORTS_START
129
 * EXPORT light_storage
130
 * EXPORTS_END
131
 */
(13-13/15)