1 // Copyright MOSSDeF, 2023 Stan Grishin <stangri@melmac.ca>
2 // This code wouldn't have been possible without help from:
3 // - [@vsviridov](https://github.com/vsviridov)
12 return "adblock-fast";
15 return "https://docs.openwrt.melmac.net/" + pkg
.Name
+ "/";
19 var getFileUrlFilesizes
= rpc
.declare({
20 object
: "luci." + pkg
.Name
,
21 method
: "getFileUrlFilesizes",
22 params
: ["name", "url"],
25 var getInitList
= rpc
.declare({
26 object
: "luci." + pkg
.Name
,
27 method
: "getInitList",
31 var getInitStatus
= rpc
.declare({
32 object
: "luci." + pkg
.Name
,
33 method
: "getInitStatus",
37 var getPlatformSupport
= rpc
.declare({
38 object
: "luci." + pkg
.Name
,
39 method
: "getPlatformSupport",
43 var _setInitAction
= rpc
.declare({
44 object
: "luci." + pkg
.Name
,
45 method
: "setInitAction",
46 params
: ["name", "action"],
47 expect
: { result
: false },
52 on: function (event
, callback
) {
53 var pair
= { event
: event
, callback
: callback
};
54 this.listeners
.push(pair
);
55 return function unsubscribe() {
56 this.listeners
= this.listeners
.filter(function (listener
) {
57 return listener
!== pair
;
61 emit: function (event
, data
) {
62 this.listeners
.forEach(function (listener
) {
63 if (listener
.event
=== event
) {
64 listener
.callback(data
);
68 setInitAction: function (name
, action
) {
69 _setInitAction(name
, action
).then(
71 this.emit("setInitAction", result
);
77 var status
= baseclass
.extend({
79 return Promise
.all([L
.resolveDefault(getInitStatus(pkg
.Name
), {})]).then(
82 status
: (data
[0] && data
[0][pkg
.Name
]) || {
89 force_dns_active
: null,
96 outputFileExists
: null,
97 outputCacheExists
: null,
98 outputGzipExists
: null,
103 var outputFile
= reply
.status
.outputFile
;
104 var outputCache
= reply
.status
.outputCache
;
106 statusNoInstall
: _("%s is not installed or not found").format(
109 statusStopped
: _("Stopped"),
110 statusStarting
: _("Starting"),
111 statusProcessing
: _("Processing lists"),
112 statusRestarting
: _("Restarting"),
113 statusForceReloading
: _("Force Reloading"),
114 statusDownloading
: _("Downloading lists"),
115 statusFail
: _("Failed to start"),
116 statusSuccess
: _("Active"),
119 var header
= E("h2", {}, _("AdBlock-Fast - Status"));
122 { class: "cbi-value-title" },
125 if (reply
.status
.version
) {
126 text
+= _("Version %s").format(reply
.status
.version
) + " - ";
127 switch (reply
.status
.status
) {
128 case "statusSuccess":
129 text
+= statusTable
[reply
.status
.status
] + ".";
132 _("Blocking %s domains (with %s).").format(
133 reply
.status
.entries
,
136 if (reply
.status
.outputGzipExists
) {
137 text
+= "<br />" + _("Compressed cache file created.");
139 if (reply
.status
.force_dns_active
) {
140 text
+= "<br />" + _("Force DNS ports:");
141 reply
.status
.force_dns_ports
.forEach((element
) => {
142 text
+= " " + element
;
147 case "statusStopped":
148 if (reply
.status
.enabled
) {
149 text
+= statusTable
[reply
.status
.status
] + ".";
152 statusTable
[reply
.status
.status
] +
157 if (reply
.status
.outputCacheExists
) {
158 text
+= "<br />" + _("Cache file found.");
159 } else if (reply
.status
.outputGzipExists
) {
160 text
+= "<br />" + _("Compressed cache file found.");
163 case "statusRestarting":
164 case "statusForceReloading":
165 case "statusDownloading":
166 case "statusProcessing":
167 text
+= statusTable
[reply
.status
.status
] + "...";
170 text
+= statusTable
[reply
.status
.status
] + ".";
174 text
= _("Not installed or not found");
176 var statusText
= E("div", {}, text
);
177 var statusField
= E("div", { class: "cbi-value-field" }, statusText
);
178 var statusDiv
= E("div", { class: "cbi-value" }, [
183 var warningsDiv
= [];
184 if (reply
.status
.warnings
&& reply
.status
.warnings
.length
) {
186 warningExternalDnsmasqConfig
: _(
187 "Use of external dnsmasq config file detected, please set '%s' option to '%s'"
188 ).format("dns", "dnsmasq.conf"),
189 warningMissingRecommendedPackages
: _(
190 "Some recommended packages are missing"
192 warningOutdatedLuciPackage
: _(
193 "The WebUI application (luci-app-adblock-fast) is outdated, please update it"
195 warningOutdatedPrincipalPackage
: _(
196 "The principal package (adblock-fast) is outdated, please update it"
198 warningInvalidCompressedCacheDir
: _(
199 "Invalid compressed cache directory '%s'"
201 warningFreeRamCheckFail
: _("Can't detect free RAM"),
203 var warningsTitle
= E(
205 { class: "cbi-value-title" },
206 _("Service Warnings")
209 reply
.status
.warnings
.forEach((element
) => {
210 if (element
.id
&& warningTable
[element
.id
])
212 warningTable
[element
.id
].format(element
.extra
|| " ") +
214 else text
+= _("Unknown warning") + "<br />";
216 var warningsText
= E("div", {}, text
);
217 var warningsField
= E(
219 { class: "cbi-value-field" },
222 warningsDiv
= E("div", { class: "cbi-value" }, [
229 if (reply
.status
.errors
&& reply
.status
.errors
.length
) {
231 errorConfigValidationFail
: _(
232 "Config (%s) validation failure!"
233 ).format("/etc/config/" + pkg
.Name
),
234 errorServiceDisabled
: _("%s is currently disabled").format(
237 errorNoDnsmasqIpset
: _(
238 "The dnsmasq ipset support is enabled, but dnsmasq is either not installed or installed dnsmasq does not support ipset"
241 "The dnsmasq ipset support is enabled, but ipset is either not installed or installed ipset does not support '%s' type"
242 ).format("hash:net"),
243 errorNoDnsmasqNftset
: _(
244 "The dnsmasq nft set support is enabled, but dnsmasq is either not installed or installed dnsmasq does not support nft set"
247 "The dnsmasq nft sets support is enabled, but nft is not installed"
249 errorNoWanGateway
: _(
250 "The %s failed to discover WAN gateway"
252 errorOutputDirCreate
: _("Failed to create directory for %s file"),
253 errorOutputFileCreate
: _("Failed to create '%s' file").format(
256 errorFailDNSReload
: _("Failed to restart/reload DNS resolver"),
257 errorSharedMemory
: _("Failed to access shared memory"),
258 errorSorting
: _("Failed to sort data file"),
259 errorOptimization
: _("Failed to optimize data file"),
260 errorAllowListProcessing
: _("Failed to process allow-list"),
261 errorDataFileFormatting
: _("Failed to format data file"),
262 errorMovingDataFile
: _(
263 "Failed to move temporary data file to '%s'"
264 ).format(outputFile
),
265 errorCreatingCompressedCache
: _(
266 "Failed to create compressed cache"
268 errorRemovingTempFiles
: _("Failed to remove temporary files"),
269 errorRestoreCompressedCache
: _("Failed to unpack compressed cache"),
270 errorRestoreCache
: _("Failed to move '%s' to '%s'").format(
275 "Failed to create block-list or restart DNS resolver"
277 errorStopping
: _("Failed to stop %s").format(pkg
.Name
),
278 errorDNSReload
: _("Failed to reload/restart DNS resolver"),
279 errorDownloadingConfigUpdate
: _(
280 "Failed to download Config Update file"
282 errorDownloadingList
: _("Failed to download %s"),
283 errorParsingConfigUpdate
: _("Failed to parse Config Update file"),
284 errorParsingList
: _("Failed to parse %s"),
285 errorNoSSLSupport
: _("No HTTPS/SSL support on device"),
286 errorCreatingDirectory
: _(
287 "Failed to create output/cache/gzip file directory"
289 errorDetectingFileType
: _("Failed to detect format %s"),
291 "No blocked list URLs nor blocked-domains enabled"
293 errorTooLittleRam
: _(
294 "Free ram (%s) is not enough to process all enabled block-lists"
299 { class: "cbi-value-title" },
303 reply
.status
.errors
.forEach((element
) => {
304 if (element
.id
&& errorTable
[element
.id
])
306 errorTable
[element
.id
].format(element
.extra
|| " ") + "!<br />";
307 else text
+= _("Unknown error") + "<br />";
309 text
+= _("Errors encountered, please check the %sREADME%s").format(
310 '<a href="' + pkg
.URL
+ '" target="_blank">',
313 var errorsText
= E("div", {}, text
);
314 var errorsField
= E("div", { class: "cbi-value-field" }, errorsText
);
315 errorsDiv
= E("div", { class: "cbi-value" }, [
321 var btn_gap
= E("span", {}, "  ");
322 var btn_gap_long
= E(
325 "        "
331 class: "btn cbi-button cbi-button-apply",
333 click: function (ev
) {
337 { class: "spinning" },
338 _("Starting %s service").format(pkg
.Name
)
341 return RPC
.setInitAction(pkg
.Name
, "start");
347 var btn_action_dl
= E(
350 class: "btn cbi-button cbi-button-apply",
352 click: function (ev
) {
356 { class: "spinning" },
357 _("Force redownloading %s block lists").format(pkg
.Name
)
360 return RPC
.setInitAction(pkg
.Name
, "dl");
366 var btn_action_pause
= E(
369 class: "btn cbi-button cbi-button-apply",
371 click: function (ev
) {
373 E("p", { class: "spinning" }, _("Pausing %s").format(pkg
.Name
)),
375 return RPC
.setInitAction(pkg
.Name
, "pause");
384 class: "btn cbi-button cbi-button-reset",
386 click: function (ev
) {
390 { class: "spinning" },
391 _("Stopping %s service").format(pkg
.Name
)
394 return RPC
.setInitAction(pkg
.Name
, "stop");
403 class: "btn cbi-button cbi-button-apply",
405 click: function (ev
) {
409 { class: "spinning" },
410 _("Enabling %s service").format(pkg
.Name
)
413 return RPC
.setInitAction(pkg
.Name
, "enable");
422 class: "btn cbi-button cbi-button-reset",
424 click: function (ev
) {
428 { class: "spinning" },
429 _("Disabling %s service").format(pkg
.Name
)
432 return RPC
.setInitAction(pkg
.Name
, "disable");
438 if (reply
.status
.enabled
) {
439 btn_enable
.disabled
= true;
440 btn_disable
.disabled
= false;
441 switch (reply
.status
.status
) {
442 case "statusSuccess":
443 btn_start
.disabled
= true;
444 btn_action_dl
.disabled
= false;
445 btn_action_pause
.disabled
= false;
446 btn_stop
.disabled
= false;
448 case "statusStopped":
449 btn_start
.disabled
= false;
450 btn_action_dl
.disabled
= true;
451 btn_action_pause
.disabled
= true;
452 btn_stop
.disabled
= true;
455 btn_start
.disabled
= false;
456 btn_action_dl
.disabled
= true;
457 btn_action_pause
.disabled
= true;
458 btn_stop
.disabled
= false;
459 btn_enable
.disabled
= true;
460 btn_disable
.disabled
= true;
464 btn_start
.disabled
= true;
465 btn_action_dl
.disabled
= true;
466 btn_action_pause
.disabled
= true;
467 btn_stop
.disabled
= true;
468 btn_enable
.disabled
= false;
469 btn_disable
.disabled
= true;
473 var buttonsTitle
= E(
475 { class: "cbi-value-title" },
478 var buttonsText
= E("div", {}, [
491 var buttonsField
= E("div", { class: "cbi-value-field" }, buttonsText
);
492 if (reply
.status
.version
) {
493 buttonsDiv
= E("div", { class: "cbi-value" }, [
499 return E("div", {}, [
511 RPC
.on("setInitAction", function (reply
) {
516 return L
.Class
.extend({
518 getFileUrlFilesizes
: getFileUrlFilesizes
,
519 getPlatformSupport
: getPlatformSupport
,