Files: 7c866dd8163bd3bd276bcec49294922c71e0f28a / bootloader.js
4653 bytesRaw
1 | var SecureUrl = require('./fetch') |
2 | var u = require('./util') |
3 | |
4 | module.exports = function (prefix, store, log) { |
5 | var appname = prefix |
6 | var wb, running = false |
7 | |
8 | //destroy everything |
9 | function scorchedEarth () { |
10 | for(var k in localStorage) { |
11 | delete localStorage[k] |
12 | } |
13 | } |
14 | function onProgress (ev) { |
15 | wb.onprogress && wb.onprogress(ev) |
16 | } |
17 | |
18 | var init = '#'+appname+'_INIT' |
19 | |
20 | return wb = { |
21 | scorchedEarth: scorchedEarth, |
22 | isInit: function () { |
23 | return location.hash.substring(0, init.length) === init |
24 | }, |
25 | setup: function () { |
26 | if(!wb.isInit()) |
27 | location.hash = init + location.hash |
28 | location.reload() |
29 | }, |
30 | reinitialize: function (cb) { |
31 | delete localStorage[appname+'_current'] |
32 | store.destroy(cb) |
33 | }, |
34 | install: function (url, cb) { |
35 | onProgress('installing from:'+url) |
36 | var id = SecureUrl.isSecureUrl(url) |
37 | if(!id) return cb(new Error('not a secure url:'+url)) |
38 | //check whether we already have this |
39 | //before downloading anything |
40 | store.get(id, function (err, data) { |
41 | if(!err) return cb(null, data, id) |
42 | SecureUrl(url, function (err, data, id) { |
43 | if(err) cb(err) |
44 | else store.add(data, id, function (err) { |
45 | cb(err, data, id) |
46 | }) |
47 | }) |
48 | }) |
49 | }, |
50 | installAndRun(url, cb) { |
51 | wb.install(url, function (err, _, id) { |
52 | if(err) cb(err) |
53 | else wb.run(id, cb) |
54 | }) |
55 | }, |
56 | add: store.add, |
57 | run: function (id, cb) { |
58 | if(!id) return cb(new Error('WebBoot.run: id must be provided')) |
59 | var _id |
60 | //if we are already running, restart |
61 | //clear out init code, if we are in setup mode |
62 | if(wb.isInit()) |
63 | location.hash = location.hash.substring(init.length) |
64 | |
65 | log.head(function (err, data) { |
66 | if(err) return cb(err) |
67 | if(data) _id = data.value |
68 | if(_id === id) |
69 | run(id) |
70 | else |
71 | log.append(id, function (err) { |
72 | if(err) return cb(err) |
73 | run(id) |
74 | }) |
75 | }) |
76 | |
77 | function run (id) { |
78 | if(running) { |
79 | //reload, and then the current version will trigger. |
80 | cb() |
81 | location.reload() |
82 | } |
83 | else |
84 | store.get(id, function (err, data) { |
85 | if(err) return cb(err) |
86 | var script = document.createElement('script') |
87 | running = true |
88 | document.body.innerHTML = '' |
89 | script.textContent = u.toUtf8(data) |
90 | document.head.appendChild(script) //run javascript. |
91 | cb() |
92 | }) |
93 | } |
94 | }, |
95 | size: function (cb) { |
96 | store.ls(function (err, ls) { |
97 | if(err) cb(err) |
98 | else cb(null, ls.reduce(function (total, item) { |
99 | return total + item.size |
100 | }, 0)) |
101 | }) |
102 | }, |
103 | //clear target amount of space. |
104 | prune: function (target, cb) { |
105 | if(!target) return cb(new Error('WebBoot.prune: size to clear must be provided')) |
106 | var cleared = 0, remove = [] |
107 | |
108 | function clear () { |
109 | var n = remove.length |
110 | while(remove.length) store.rm(remove.shift(), function () { |
111 | if(--n) return |
112 | if(cleared < target) |
113 | cb(new Error('could not clear requested space'), cleared) |
114 | else |
115 | cb(null, cleared) |
116 | }) |
117 | } |
118 | |
119 | store.ls(function (err, ls) { |
120 | if(err) return cb(err) |
121 | log.unfiltered(function (err, unfiltered) { |
122 | var stored = unfiltered.reverse() |
123 | for(var i = 0; i < stored.length; i++) { |
124 | var id = stored[i].value |
125 | var item = ls.find(function (e) { |
126 | return e.id === id |
127 | }) |
128 | |
129 | if(item) { |
130 | cleared += item.size |
131 | remove.push(id) |
132 | if(cleared >= target) return clear() |
133 | } |
134 | } |
135 | clear() |
136 | }) |
137 | }) |
138 | }, |
139 | |
140 | version: require('./package.json').version, |
141 | remove: store.rm, |
142 | has: store.has, |
143 | versions: function (cb) { |
144 | log.filtered(function (err, ls) { |
145 | if(err) return cb(err) |
146 | else if(ls.length) cb(null, ls) |
147 | else { |
148 | console.log('restore from legacy log...') |
149 | var versions = u.parse(localStorage[appname+'_versions']) |
150 | var n = Object.keys(versions).length |
151 | for(var ts in versions) { |
152 | log._append(versions[ts], function () { |
153 | if(--n) return |
154 | //try again |
155 | log.filtered(cb) |
156 | }) |
157 | } |
158 | } |
159 | }) |
160 | }, |
161 | history: log.unfiltered, |
162 | current: log.head, |
163 | append: log.append, |
164 | revert: log.revert, |
165 | onprogress: null |
166 | } |
167 | } |
168 | |
169 | |
170 | |
171 | |
172 | |
173 |
Built with git-ssb-web