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 statusError
: _("Error"),
116 statusWarning
: _("Warning"),
117 statusFail
: _("Fail"),
118 statusSuccess
: _("Active"),
121 var header
= E("h2", {}, _("AdBlock-Fast - Status"));
124 { class: "cbi-value-title" },
127 if (reply
.status
.version
) {
128 text
+= _("Version %s").format(reply
.status
.version
) + " - ";
129 switch (reply
.status
.status
) {
130 case "statusSuccess":
131 text
+= statusTable
[reply
.status
.status
] + ".";
134 _("Blocking %s domains (with %s).").format(
135 reply
.status
.entries
,
138 if (reply
.status
.outputGzipExists
) {
139 text
+= "<br />" + _("Compressed cache file created.");
141 if (reply
.status
.force_dns_active
) {
142 text
+= "<br />" + _("Force DNS ports:");
143 reply
.status
.force_dns_ports
.forEach((element
) => {
144 text
+= " " + element
;
149 case "statusStopped":
150 if (reply
.status
.enabled
) {
151 text
+= statusTable
[reply
.status
.status
] + ".";
154 statusTable
[reply
.status
.status
] +
159 if (reply
.status
.outputCacheExists
) {
160 text
+= "<br />" + _("Cache file found.");
161 } else if (reply
.status
.outputGzipExists
) {
162 text
+= "<br />" + _("Compressed cache file found.");
165 case "statusRestarting":
166 case "statusForceReloading":
167 case "statusDownloading":
168 case "statusProcessing":
169 text
+= statusTable
[reply
.status
.status
] + "...";
172 text
+= statusTable
[reply
.status
.status
] + ".";
176 text
= _("Not installed or not found");
178 var statusText
= E("div", {}, text
);
179 var statusField
= E("div", { class: "cbi-value-field" }, statusText
);
180 var statusDiv
= E("div", { class: "cbi-value" }, [
185 var warningsDiv
= [];
186 if (reply
.status
.warnings
&& reply
.status
.warnings
.length
) {
188 warningExternalDnsmasqConfig
: _(
189 "Use of external dnsmasq config file detected, please set '%s' option to '%s'"
190 ).format("dns", "dnsmasq.conf"),
191 warningMissingRecommendedPackages
: _(
192 "Some recommended packages are missing"
195 var warningsTitle
= E(
197 { class: "cbi-value-title" },
198 _("Service Warnings")
201 reply
.status
.warnings
.forEach((element
) => {
203 warningTable
[element
.id
].format(element
.extra
|| " ") + "<br />";
205 var warningsText
= E("div", {}, text
);
206 var warningsField
= E(
208 { class: "cbi-value-field" },
211 warningsDiv
= E("div", { class: "cbi-value" }, [
218 if (reply
.status
.errors
&& reply
.status
.errors
.length
) {
220 errorConfigValidationFail
: _(
221 "Config (%s) validation failure!"
222 ).format("/etc/config/" + pkg
.Name
),
223 errorServiceDisabled
: _("%s is currently disabled").format(
226 errorNoDnsmasqIpset
: _(
227 "The dnsmasq ipset support is enabled, but dnsmasq is either not installed or installed dnsmasq does not support ipset"
230 "The dnsmasq ipset support is enabled, but ipset is either not installed or installed ipset does not support '%s' type"
231 ).format("hash:net"),
232 errorNoDnsmasqNftset
: _(
233 "The dnsmasq nft set support is enabled, but dnsmasq is either not installed or installed dnsmasq does not support nft set"
236 "The dnsmasq nft sets support is enabled, but nft is not installed"
238 errorNoWanGateway
: _(
239 "The %s failed to discover WAN gateway"
241 errorOutputDirCreate
: _("Failed to create directory for %s file"),
242 errorOutputFileCreate
: _("Failed to create '%s' file").format(
245 errorFailDNSReload
: _("Failed to restart/reload DNS resolver"),
246 errorSharedMemory
: _("Failed to access shared memory"),
247 errorSorting
: _("Failed to sort data file"),
248 errorOptimization
: _("Failed to optimize data file"),
249 errorAllowListProcessing
: _("Failed to process allow-list"),
250 errorDataFileFormatting
: _("Failed to format data file"),
251 errorMovingDataFile
: _(
252 "Failed to move temporary data file to '%s'"
253 ).format(outputFile
),
254 errorCreatingCompressedCache
: _(
255 "Failed to create compressed cache"
257 errorRemovingTempFiles
: _("Failed to remove temporary files"),
258 errorRestoreCompressedCache
: _("Failed to unpack compressed cache"),
259 errorRestoreCache
: _("Failed to move '%s' to '%s'").format(
264 "Failed to create block-list or restart DNS resolver"
266 errorStopping
: _("Failed to stop %s").format(pkg
.Name
),
267 errorDNSReload
: _("Failed to reload/restart DNS resolver"),
268 errorDownloadingConfigUpdate
: _(
269 "Failed to download Config Update file"
271 errorDownloadingList
: _("Failed to download %s"),
272 errorParsingConfigUpdate
: _("Failed to parse Config Update file"),
273 errorParsingList
: _("Failed to parse %s"),
274 errorNoSSLSupport
: _("No HTTPS/SSL support on device"),
275 errorCreatingDirectory
: _(
276 "Failed to create output/cache/gzip file directory"
278 errorDetectingFileType
: _("Failed to detect format %s"),
280 "No blocked list URLs nor blocked-domains enabled"
285 { class: "cbi-value-title" },
289 reply
.status
.errors
.forEach((element
) => {
291 errorTable
[element
.id
].format(element
.extra
|| " ") + "<br />";
293 text
+= _("Errors encountered, please check the %sREADME%s!").format(
294 '<a href="' + pkg
.URL
+ '" target="_blank">',
297 var errorsText
= E("div", {}, text
);
298 var errorsField
= E("div", { class: "cbi-value-field" }, errorsText
);
299 errorsDiv
= E("div", { class: "cbi-value" }, [
305 var btn_gap
= E("span", {}, "  ");
306 var btn_gap_long
= E(
309 "        "
315 class: "btn cbi-button cbi-button-apply",
317 click: function (ev
) {
321 { class: "spinning" },
322 _("Starting %s service").format(pkg
.Name
)
325 return RPC
.setInitAction(pkg
.Name
, "start");
334 class: "btn cbi-button cbi-button-apply",
336 click: function (ev
) {
340 { class: "spinning" },
341 _("Force re-downloading %s block lists").format(pkg
.Name
)
344 return RPC
.setInitAction(pkg
.Name
, "dl");
347 _("Force Re-Download")
353 class: "btn cbi-button cbi-button-reset",
355 click: function (ev
) {
359 { class: "spinning" },
360 _("Stopping %s service").format(pkg
.Name
)
363 return RPC
.setInitAction(pkg
.Name
, "stop");
372 class: "btn cbi-button cbi-button-apply",
374 click: function (ev
) {
378 { class: "spinning" },
379 _("Enabling %s service").format(pkg
.Name
)
382 return RPC
.setInitAction(pkg
.Name
, "enable");
391 class: "btn cbi-button cbi-button-reset",
393 click: function (ev
) {
397 { class: "spinning" },
398 _("Disabling %s service").format(pkg
.Name
)
401 return RPC
.setInitAction(pkg
.Name
, "disable");
407 if (reply
.status
.enabled
) {
408 btn_enable
.disabled
= true;
409 btn_disable
.disabled
= false;
410 switch (reply
.status
.status
) {
411 case "statusSuccess":
412 btn_start
.disabled
= true;
413 btn_action
.disabled
= false;
414 btn_stop
.disabled
= false;
416 case "statusStopped":
417 btn_start
.disabled
= false;
418 btn_action
.disabled
= true;
419 btn_stop
.disabled
= true;
422 btn_start
.disabled
= false;
423 btn_action
.disabled
= true;
424 btn_stop
.disabled
= false;
425 btn_enable
.disabled
= true;
426 btn_disable
.disabled
= true;
430 btn_start
.disabled
= true;
431 btn_action
.disabled
= true;
432 btn_stop
.disabled
= true;
433 btn_enable
.disabled
= false;
434 btn_disable
.disabled
= true;
438 var buttonsTitle
= E(
440 { class: "cbi-value-title" },
443 var buttonsText
= E("div", {}, [
454 var buttonsField
= E("div", { class: "cbi-value-field" }, buttonsText
);
455 if (reply
.status
.version
) {
456 buttonsDiv
= E("div", { class: "cbi-value" }, [
462 return E("div", {}, [
474 RPC
.on("setInitAction", function (reply
) {
479 return L
.Class
.extend({
481 getFileUrlFilesizes
: getFileUrlFilesizes
,
482 getPlatformSupport
: getPlatformSupport
,