123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- // Copyright MOSSDeF, 2023 Stan Grishin <stangri@melmac.ca>
- // This code wouldn't have been possible without help from:
- // - [@stokito](https://github.com/stokito)
- // - [@vsviridov](https://github.com/vsviridov)
- // noinspection JSAnnotator
- "require ui";
- "require rpc";
- "require form";
- "require baseclass";
- var pkg = {
- get Name() {
- return "https-dns-proxy";
- },
- get ReadmeCompat() {
- return "";
- },
- get URL() {
- return (
- "https://docs.openwrt.melmac.net/" +
- pkg.Name +
- "/" +
- (pkg.ReadmeCompat ? pkg.ReadmeCompat + "/" : "")
- );
- },
- templateToRegexp: function (template) {
- return RegExp(
- "^" +
- template
- .split(/(\{\w+\})/g)
- .map((part) => {
- let placeholder = part.match(/^\{(\w+)\}$/);
- if (placeholder) return `(?<${placeholder[1]}>.*?)`;
- else return part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
- })
- .join("") +
- "$"
- );
- },
- templateToResolver: function (template, args) {
- return template.replace(/{(\w+)}/g, (_, v) => args[v]);
- },
- };
- const getInitList = rpc.declare({
- object: "luci." + pkg.Name,
- method: "getInitList",
- params: ["name"],
- });
- const getInitStatus = rpc.declare({
- object: "luci." + pkg.Name,
- method: "getInitStatus",
- params: ["name"],
- });
- const getPlatformSupport = rpc.declare({
- object: "luci." + pkg.Name,
- method: "getPlatformSupport",
- params: ["name"],
- });
- const getProviders = rpc.declare({
- object: "luci." + pkg.Name,
- method: "getProviders",
- params: ["name"],
- });
- const getRuntime = rpc.declare({
- object: "luci." + pkg.Name,
- method: "getRuntime",
- params: ["name"],
- });
- const _setInitAction = rpc.declare({
- object: "luci." + pkg.Name,
- method: "setInitAction",
- params: ["name", "action"],
- expect: { result: false },
- });
- var RPC = {
- listeners: [],
- on: function (event, callback) {
- var pair = { event: event, callback: callback };
- this.listeners.push(pair);
- return function unsubscribe() {
- this.listeners = this.listeners.filter(function (listener) {
- return listener !== pair;
- });
- }.bind(this);
- },
- emit: function (event, data) {
- this.listeners.forEach(function (listener) {
- if (listener.event === event) {
- listener.callback(data);
- }
- });
- },
- getInitList: function (name) {
- getInitList(name).then(
- function (result) {
- this.emit("getInitList", result);
- }.bind(this)
- );
- },
- getInitStatus: function (name) {
- getInitStatus(name).then(
- function (result) {
- this.emit("getInitStatus", result);
- }.bind(this)
- );
- },
- getPlatformSupport: function (name) {
- getPlatformSupport(name).then(
- function (result) {
- this.emit("getPlatformSupport", result);
- }.bind(this)
- );
- },
- getProviders: function (name) {
- getProviders(name).then(
- function (result) {
- this.emit("getProviders", result);
- }.bind(this)
- );
- },
- getRuntime: function (name) {
- getRuntime(name).then(
- function (result) {
- this.emit("getRuntime", result);
- }.bind(this)
- );
- },
- setInitAction: function (name, action) {
- _setInitAction(name, action).then(
- function (result) {
- this.emit("setInitAction", result);
- }.bind(this)
- );
- },
- };
- var status = baseclass.extend({
- render: function () {
- return Promise.all([
- L.resolveDefault(getInitStatus(pkg.Name), {}),
- L.resolveDefault(getProviders(pkg.Name), {}),
- L.resolveDefault(getRuntime(pkg.Name), {}),
- ]).then(function (data) {
- var text;
- var reply = {
- status: (data[0] && data[0][pkg.Name]) || {
- enabled: null,
- running: null,
- force_dns_active: null,
- version: null,
- },
- providers: (data[1] && data[1][pkg.Name]) || { providers: [] },
- runtime: (data[2] && data[2][pkg.Name]) || { instances: [] },
- };
- reply.providers.sort(function (a, b) {
- return _(a.title).localeCompare(_(b.title));
- });
- reply.providers.push({
- title: "Custom",
- template: "{option}",
- params: { option: { type: "text" } },
- });
- var header = E("h2", {}, _("HTTPS DNS Proxy - Status"));
- var statusTitle = E(
- "label",
- { class: "cbi-value-title" },
- _("Service Status")
- );
- if (reply.status.version) {
- if (reply.status.running) {
- text = _("Version %s - Running.").format(reply.status.version);
- if (reply.status.force_dns_active) {
- text += "<br />" + _("Force DNS ports:");
- reply.status.force_dns_ports.forEach((element) => {
- text += " " + element;
- });
- text += ".";
- }
- } else {
- if (reply.status.enabled) {
- text = _("Version %s - Stopped.").format(reply.status.version);
- } else {
- text = _("Version %s - Stopped (Disabled).").format(
- reply.status.version
- );
- }
- }
- } else {
- text = _("Not installed or not found");
- }
- var statusText = E("div", {}, text);
- var statusField = E("div", { class: "cbi-value-field" }, statusText);
- var statusDiv = E("div", { class: "cbi-value" }, [
- statusTitle,
- statusField,
- ]);
- var instancesDiv = [];
- if (reply.runtime.instances) {
- var instancesTitle = E(
- "label",
- { class: "cbi-value-title" },
- _("Service Instances")
- );
- text = _("See the %sREADME%s for details.").format(
- '<a href="' +
- pkg.URL +
- '#a-word-about-default-routing " target="_blank">',
- "</a>"
- );
- var instancesDescr = E("div", { class: "cbi-value-description" }, "");
- text = "";
- Object.values(reply.runtime.instances).forEach((element) => {
- var resolver;
- var address;
- var port;
- var name;
- var option;
- var found;
- element.command.forEach((param, index, arr) => {
- if (param === "-r") resolver = arr[index + 1];
- if (param === "-a") address = arr[index + 1];
- if (param === "-p") port = arr[index + 1];
- });
- resolver = resolver || "Unknown";
- address = address || "127.0.0.1";
- port = port || "Unknown";
- reply.providers.forEach((prov) => {
- let regexp = pkg.templateToRegexp(prov.template);
- if (!found && regexp.test(resolver)) {
- found = true;
- name = _(prov.title);
- let match = resolver.match(regexp);
- if (match[1] != null) {
- if (
- prov.params &&
- prov.params.option &&
- prov.params.option.options
- ) {
- prov.params.option.options.forEach((opt) => {
- if (opt.value === match[1]) option = _(opt.description);
- });
- name += " (" + option + ")";
- } else {
- if (match[1] !== "") name += " (" + match[1] + ")";
- }
- }
- }
- });
- if (address === "127.0.0.1")
- text += _("%s%s%s proxy on port %s.%s").format(
- "<strong>",
- name,
- "</strong>",
- port,
- "<br />"
- );
- else
- text += _("%s%s%s proxy at %s on port %s.%s").format(
- "<strong>",
- name,
- "</strong>",
- address,
- port,
- "<br />"
- );
- });
- var instancesText = E("div", {}, text);
- var instancesField = E("div", { class: "cbi-value-field" }, [
- instancesText,
- instancesDescr,
- ]);
- instancesDiv = E("div", { class: "cbi-value" }, [
- instancesTitle,
- instancesField,
- ]);
- }
- var btn_gap = E("span", {}, "  ");
- var btn_gap_long = E(
- "span",
- {},
- "        "
- );
- var btn_start = E(
- "button",
- {
- class: "btn cbi-button cbi-button-apply",
- disabled: true,
- click: function (ev) {
- ui.showModal(null, [
- E(
- "p",
- { class: "spinning" },
- _("Starting %s service").format(pkg.Name)
- ),
- ]);
- return RPC.setInitAction(pkg.Name, "start");
- },
- },
- _("Start")
- );
- var btn_action = E(
- "button",
- {
- class: "btn cbi-button cbi-button-apply",
- disabled: true,
- click: function (ev) {
- ui.showModal(null, [
- E(
- "p",
- { class: "spinning" },
- _("Restarting %s service").format(pkg.Name)
- ),
- ]);
- return RPC.setInitAction(pkg.Name, "restart");
- },
- },
- _("Restart")
- );
- var btn_stop = E(
- "button",
- {
- class: "btn cbi-button cbi-button-reset",
- disabled: true,
- click: function (ev) {
- ui.showModal(null, [
- E(
- "p",
- { class: "spinning" },
- _("Stopping %s service").format(pkg.Name)
- ),
- ]);
- return RPC.setInitAction(pkg.Name, "stop");
- },
- },
- _("Stop")
- );
- var btn_enable = E(
- "button",
- {
- class: "btn cbi-button cbi-button-apply",
- disabled: true,
- click: function (ev) {
- ui.showModal(null, [
- E(
- "p",
- { class: "spinning" },
- _("Enabling %s service").format(pkg.Name)
- ),
- ]);
- return RPC.setInitAction(pkg.Name, "enable");
- },
- },
- _("Enable")
- );
- var btn_disable = E(
- "button",
- {
- class: "btn cbi-button cbi-button-reset",
- disabled: true,
- click: function (ev) {
- ui.showModal(null, [
- E(
- "p",
- { class: "spinning" },
- _("Disabling %s service").format(pkg.Name)
- ),
- ]);
- return RPC.setInitAction(pkg.Name, "disable");
- },
- },
- _("Disable")
- );
- if (reply.status.enabled) {
- btn_enable.disabled = true;
- btn_disable.disabled = false;
- if (reply.status.running) {
- btn_start.disabled = true;
- btn_action.disabled = false;
- btn_stop.disabled = false;
- } else {
- btn_start.disabled = false;
- btn_action.disabled = true;
- btn_stop.disabled = true;
- }
- } else {
- btn_start.disabled = true;
- btn_action.disabled = true;
- btn_stop.disabled = true;
- btn_enable.disabled = false;
- btn_disable.disabled = true;
- }
- var buttonsTitle = E(
- "label",
- { class: "cbi-value-title" },
- _("Service Control")
- );
- var buttonsText = E("div", {}, [
- btn_start,
- btn_gap,
- btn_action,
- btn_gap,
- btn_stop,
- btn_gap_long,
- btn_enable,
- btn_gap,
- btn_disable,
- ]);
- var buttonsField = E("div", { class: "cbi-value-field" }, buttonsText);
- var buttonsDiv = reply.status.version
- ? E("div", { class: "cbi-value" }, [buttonsTitle, buttonsField])
- : "";
- return E("div", {}, [header, statusDiv, instancesDiv, buttonsDiv]);
- });
- },
- });
- RPC.on("setInitAction", function (reply) {
- ui.hideModal();
- location.reload();
- });
- return L.Class.extend({
- status: status,
- pkg: pkg,
- getInitStatus: getInitStatus,
- getPlatformSupport: getPlatformSupport,
- getProviders: getProviders,
- getRuntime: getRuntime,
- });
|