1 // Copyright 2022 Stan Grishin <stangri@melmac.ca>
2 // This code wouldn't have been possible without help from [@vsviridov](https://github.com/vsviridov)
10 get Name() { return 'simple-adblock'; },
11 get URL() { return 'https://docs.openwrt.melmac.net/' + pkg
.Name
+ '/'; },
14 var getInitList
= rpc
.declare({
15 object
: "luci." + pkg
.Name
,
16 method
: "getInitList",
20 var getInitStatus
= rpc
.declare({
21 object
: "luci." + pkg
.Name
,
22 method
: "getInitStatus",
26 var getPlatformSupport
= rpc
.declare({
27 object
: "luci." + pkg
.Name
,
28 method
: "getPlatformSupport",
32 var _setInitAction
= rpc
.declare({
33 object
: "luci." + pkg
.Name
,
34 method
: "setInitAction",
35 params
: ["name", "action"],
36 expect
: { result
: false },
41 on
: function on(event
, callback
) {
42 var pair
= { event
: event
, callback
: callback
}
43 this.listeners
.push(pair
);
44 return function unsubscribe() {
45 this.listeners
= this.listeners
.filter(function (listener
) {
46 return listener
!== pair
;
50 emit
: function emit(event
, data
) {
51 this.listeners
.forEach(function (listener
) {
52 if (listener
.event
=== event
) {
53 listener
.callback(data
);
57 getInitList
: function getInitList(name
) {
58 getInitList(name
).then(function (result
) {
59 this.emit('getInitList', result
);
62 getInitStatus
: function getInitStatus(name
) {
63 getInitStatus(name
).then(function (result
) {
64 this.emit('getInitStatus', result
);
67 getPlatformSupport
: function getPlatformSupport(name
) {
68 getPlatformSupport(name
).then(function (result
) {
69 this.emit('getPlatformSupport', result
);
72 setInitAction
: function setInitAction(name
, action
) {
73 _setInitAction(name
, action
).then(function (result
) {
74 this.emit('setInitAction', result
);
79 var status
= baseclass
.extend({
82 L
.resolveDefault(getInitStatus(pkg
.Name
), {}),
83 ]).then(function (data
) {
84 var replyStatus
= data
[0];
86 var reply
= replyStatus
[pkg
.Name
];
87 var outputFile
= reply
.outputFile
;
88 var outputCache
= reply
.outputCache
;
90 statusNoInstall
: _("%s is not installed or not found").format(pkg
.Name
),
91 statusStopped
: _("Stopped"),
92 statusStarting
: _("Starting"),
93 statusProcessing
: _("Processing lists"),
94 statusRestarting
: _("Restarting"),
95 statusForceReloading
: _("Force Reloading"),
96 statusDownloading
: _("Downloading lists"),
97 statusError
: _("Error"),
98 statusWarning
: _("Warning"),
99 statusFail
: _("Fail"),
100 statusSuccess
: _("Active")
103 var header
= E('h2', {}, _("Simple AdBlock - Status"))
104 var statusTitle
= E('label', { class: 'cbi-value-title' }, _("Service Status"));
106 text
+= _("Version %s").format(reply
.version
) + " - ";
107 switch (reply
.status
) {
108 case 'statusSuccess':
109 text
+= statusTable
[reply
.status
] + ".";
110 text
+= "<br />" + _("Blocking %s domains (with %s).").format(reply
.entries
, reply
.dns
);
111 if (reply
.outputGzipExists
) {
112 text
+= "<br />" + _("Compressed cache file created.");
114 if (reply
.force_dns_active
) {
115 text
+= "<br />" + _("Force DNS ports:");
116 reply
.force_dns_ports
.forEach(element
=> {
117 text
+= " " + element
;
122 case 'statusStopped':
124 text
+= statusTable
[reply
.status
] + ".";
127 text
+= statusTable
[reply
.status
] + _("disabled") + "."
129 if (reply
.outputCacheExists
) {
130 text
+= "<br />" + _("Cache file found.");
132 else if (reply
.outputGzipExists
) {
133 text
+= "<br />" + _("Compressed cache file found.");
136 case 'statusRestarting':
137 case 'statusForceReloading':
138 case 'statusDownloading':
139 case 'statusProcessing':
140 text
+= statusTable
[reply
.status
] + "...";
143 text
+= statusTable
[reply
.status
] + ".";
148 text
= _("Not installed or not found");
150 var statusText
= E('div', {}, text
);
151 var statusField
= E('div', { class: 'cbi-value-field' }, statusText
);
152 var statusDiv
= E('div', { class: 'cbi-value' }, [statusTitle
, statusField
]);
154 var warningsDiv
= [];
155 if (reply
.warnings
&& reply
.warnings
.length
) {
157 warningExternalDnsmasqConfig
: _("use of external dnsmasq config file detected, please set '%s' option to '%s'").format("dns", "dnsmasq.conf"),
158 warningMissingRecommendedPackages
: _("some recommended packages are missing")
160 var warningsTitle
= E('label', { class: 'cbi-value-title' }, _("Service Warnings"));
162 (reply
.warnings
).forEach(element
=> {
163 text
+= (warningTable
[element
.id
]).format(element
.extra
|| ' ') + "<br />";
165 var warningsText
= E('div', {}, text
);
166 var warningsField
= E('div', { class: 'cbi-value-field' }, warningsText
);
167 warningsDiv
= E('div', { class: 'cbi-value' }, [warningsTitle
, warningsField
]);
171 if (reply
.errors
&& reply
.errors
.length
) {
173 errorConfigValidationFail
: _("config (%s) validation failure!").format('/etc/config/' + pkg
.Name
),
174 errorServiceDisabled
: _("%s is currently disabled").format(pkg
.Name
),
175 errorNoDnsmasqIpset
: _("dnsmasq ipset support is enabled, but dnsmasq is either not installed or installed dnsmasq does not support ipset"),
176 errorNoIpset
: _("dnsmasq ipset support is enabled, but ipset is either not installed or installed ipset does not support '%s' type").format("hash:net"),
177 errorNoDnsmasqNftset
: _("dnsmasq nft set support is enabled, but dnsmasq is either not installed or installed dnsmasq does not support nft set"),
178 errorNoNft
: _("dnsmasq nft sets support is enabled, but nft is not installed"),
179 errorNoWanGateway
: _("the %s failed to discover WAN gateway").format(pkg
.Name
),
180 errorOutputDirCreate
: _("failed to create directory for %s file"),
181 errorOutputFileCreate
: _("failed to create '%s' file").format(outputFile
),
182 errorFailDNSReload
: _("failed to restart/reload DNS resolver"),
183 errorSharedMemory
: _("failed to access shared memory"),
184 errorSorting
: _("failed to sort data file"),
185 errorOptimization
: _("failed to optimize data file"),
186 errorAllowListProcessing
: _("failed to process allow-list"),
187 errorDataFileFormatting
: _("failed to format data file"),
188 errorMovingDataFile
: _("failed to move temporary data file to '%s'").format(outputFile
),
189 errorCreatingCompressedCache
: _("failed to create compressed cache"),
190 errorRemovingTempFiles
: _("failed to remove temporary files"),
191 errorRestoreCompressedCache
: _("failed to unpack compressed cache"),
192 errorRestoreCache
: _("failed to move '%s' to '%s'").format(outputCache
, outputFile
),
193 errorOhSnap
: _("failed to create block-list or restart DNS resolver"),
194 errorStopping
: _("failed to stop %s").format(pkg
.Name
),
195 errorDNSReload
: _("failed to reload/restart DNS resolver"),
196 errorDownloadingConfigUpdate
: _("failed to download Config Update file"),
197 errorDownloadingList
: _("failed to download"),
198 errorParsingConfigUpdate
: _("failed to parse Config Update file"),
199 errorParsingList
: _("failed to parse"),
200 errorNoSSLSupport
: _("no HTTPS/SSL support on device"),
201 errorCreatingDirectory
: _("failed to create output/cache/gzip file directory")
203 var errorsTitle
= E('label', { class: 'cbi-value-title' }, _("Service Errors"));
205 (reply
.errors
).forEach(element
=> {
206 text
+= (errorTable
[element
.id
]).format(element
.extra
|| ' ') + "<br />";
208 var errorsText
= E('div', {}, text
);
209 var errorsField
= E('div', { class: 'cbi-value-field' }, errorsText
);
210 errorsDiv
= E('div', { class: 'cbi-value' }, [errorsTitle
, errorsField
]);
213 var btn_gap
= E('span', {}, '  ');
214 var btn_gap_long
= E('span', {}, '        ');
216 var btn_start
= E('button', {
217 'class': 'btn cbi-button cbi-button-apply',
219 click: function (ev
) {
221 E('p', { 'class': 'spinning' }, _('Starting %s service').format(pkg
.Name
))
223 return RPC
.setInitAction(pkg
.Name
, 'start');
227 var btn_action
= E('button', {
228 'class': 'btn cbi-button cbi-button-apply',
230 click: function (ev
) {
232 E('p', { 'class': 'spinning' }, _('Force re-downloading %s block lists').format(pkg
.Name
))
234 return RPC
.setInitAction(pkg
.Name
, 'dl');
236 }, _('Force Re-Download'));
238 var btn_stop
= E('button', {
239 'class': 'btn cbi-button cbi-button-reset',
241 click: function (ev
) {
243 E('p', { 'class': 'spinning' }, _('Stopping %s service').format(pkg
.Name
))
245 return RPC
.setInitAction(pkg
.Name
, 'stop');
249 var btn_enable
= E('button', {
250 'class': 'btn cbi-button cbi-button-apply',
252 click: function (ev
) {
254 E('p', { 'class': 'spinning' }, _('Enabling %s service').format(pkg
.Name
))
256 return RPC
.setInitAction(pkg
.Name
, 'enable');
260 var btn_disable
= E('button', {
261 'class': 'btn cbi-button cbi-button-reset',
263 click: function (ev
) {
265 E('p', { 'class': 'spinning' }, _('Disabling %s service').format(pkg
.Name
))
267 return RPC
.setInitAction(pkg
.Name
, 'disable');
272 btn_enable
.disabled
= true;
273 btn_disable
.disabled
= false;
274 switch (reply
.status
) {
275 case 'statusSuccess':
276 btn_start
.disabled
= true;
277 btn_action
.disabled
= false;
278 btn_stop
.disabled
= false;
280 case 'statusStopped':
281 btn_start
.disabled
= false;
282 btn_action
.disabled
= true;
283 btn_stop
.disabled
= true;
286 btn_start
.disabled
= false;
287 btn_action
.disabled
= true;
288 btn_stop
.disabled
= false;
289 btn_enable
.disabled
= true;
290 btn_disable
.disabled
= true;
295 btn_start
.disabled
= true;
296 btn_action
.disabled
= true;
297 btn_stop
.disabled
= true;
298 btn_enable
.disabled
= false;
299 btn_disable
.disabled
= true;
303 var buttonsTitle
= E('label', { class: 'cbi-value-title' }, _("Service Control"))
304 var buttonsText
= E('div', {}, [btn_start
, btn_gap
, btn_action
, btn_gap
, btn_stop
, btn_gap_long
, btn_enable
, btn_gap
, btn_disable
]);
305 var buttonsField
= E('div', { class: 'cbi-value-field' }, buttonsText
);
307 buttonsDiv
= E('div', { class: 'cbi-value' }, [buttonsTitle
, buttonsField
]);
310 return E('div', {}, [header
, statusDiv
, warningsDiv
, errorsDiv
, buttonsDiv
]);
315 RPC
.on('setInitAction', function (reply
) {
320 return L
.Class
.extend({
322 getPlatformSupport
: getPlatformSupport