From 7574bb6ebff609b9a2889fc573ce3edce256e030 Mon Sep 17 00:00:00 2001 From: Shulhan Date: Mon, 18 May 2020 21:47:45 +0700 Subject: all: implement the user interface to change configuration This is the first web UI (wui) where user can change configuration on the fly. The wui is implemented using svelte.dev and can be accessed on http://127.0.0.1:5380. --- .gitignore | 5 +- Makefile | 5 +- _doc/rescached.cfg.adoc | 13 +- _www/.gitignore | 4 + _www/package-lock.json | 598 +++++++++++++++++++++++++++++++++++++++++++ _www/package.json | 21 ++ _www/public/favicon.png | Bin 0 -> 12685 bytes _www/public/global.css | 66 +++++ _www/public/index.html | 17 ++ _www/rollup.config.js | 71 +++++ _www/src/App.svelte | 53 ++++ _www/src/Environment.svelte | 248 ++++++++++++++++++ _www/src/InputAddress.svelte | 48 ++++ _www/src/InputNumber.svelte | 35 +++ _www/src/LabelHint.svelte | 46 ++++ _www/src/main.js | 10 + cmd/rescached/main.go | 21 +- cmd/rescached/rescached.cfg | 28 +- go.mod | 2 +- go.sum | 4 +- internal/generate_memfs.go | 31 +++ options.go | 74 +++++- rescached.go | 51 +++- rescached_httpd.go | 144 +++++++++++ 24 files changed, 1547 insertions(+), 48 deletions(-) create mode 100644 _www/.gitignore create mode 100644 _www/package-lock.json create mode 100644 _www/package.json create mode 100644 _www/public/favicon.png create mode 100644 _www/public/global.css create mode 100644 _www/public/index.html create mode 100644 _www/rollup.config.js create mode 100644 _www/src/App.svelte create mode 100644 _www/src/Environment.svelte create mode 100644 _www/src/InputAddress.svelte create mode 100644 _www/src/InputNumber.svelte create mode 100644 _www/src/LabelHint.svelte create mode 100644 _www/src/main.js create mode 100644 internal/generate_memfs.go create mode 100644 rescached_httpd.go diff --git a/.gitignore b/.gitignore index b2ea592..4335f28 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,11 @@ /README.html /TODO -/cover.html -/cover.out /_doc/benchmark.html /_doc/rescached.cfg.5.gz /_doc/resolver.1.gz +/cmd/rescached/memfs.go +/cover.html +/cover.out /heap* /rescached /rescached.1.gz diff --git a/Makefile b/Makefile index f723d09..0d9ba2c 100644 --- a/Makefile +++ b/Makefile @@ -57,9 +57,12 @@ coverbrowse: $(COVER_HTML) lint: -golangci-lint run --enable-all ./... -$(RESCACHED_BIN): $(SRC) +$(RESCACHED_BIN): cmd/rescached/memfs.go $(SRC) go build $(DEBUG) ./cmd/rescached +cmd/rescached/memfs.go: internal/generate_memfs.go _www/public/* + go run ./internal/generate_memfs.go + $(RESOLVER_BIN): $(SRC) go build $(DEBUG) ./cmd/resolver diff --git a/_doc/rescached.cfg.adoc b/_doc/rescached.cfg.adoc index 4a28bcb..0408441 100644 --- a/_doc/rescached.cfg.adoc +++ b/_doc/rescached.cfg.adoc @@ -19,7 +19,6 @@ rescached.cfg - Configuration for rescached service == DESCRIPTION These file configure the behaviour of *rescached*(1) service. -In those file you can see some comment for any option and some possible value. This section will explain more about each option and how they effect +rescached+. @@ -37,6 +36,13 @@ in square bracket: This group of options contain the main configuration that related to rescached. +[[wui.listen]] +==== +wui.listen+ + +Format:: [host]:port +Default:: 127.0.0.1:5380 +Description:: The address to listen for web user interface. + [[dir.hosts]] ==== +dir.hosts+ @@ -158,7 +164,7 @@ Description:: Port to serve DNS over HTTP. Format:: Number Default:: 853 -Description:: Port to listen for DNS over TLS. +Description:: Port to serve DNS over TLS. [[tls.certificate]] ==== +tls.certificate+ @@ -202,6 +208,7 @@ Description:: Delay for pruning caches. Every N seconds/minutes/hours, rescached will traverse all caches and remove response that has not been accessed less than +cache.prune_threshold+. +Its value must be equal or greater than 1 hour (3600 seconds). [[cache.prune_threshold]] ==== +cache.prune_threshold+ @@ -209,7 +216,7 @@ caches and remove response that has not been accessed less than Format:: Duration with time unit. Valid time units are "s", "m", "h". Default:: -1h Description:: The duration when the cache will be considered expired. -Its value must be negative and less than -1 minute. +Its value must be negative and greater or equal than -1 hour (-3600 seconds). == EXAMPLE diff --git a/_www/.gitignore b/_www/.gitignore new file mode 100644 index 0000000..da93220 --- /dev/null +++ b/_www/.gitignore @@ -0,0 +1,4 @@ +/node_modules/ +/public/build/ + +.DS_Store diff --git a/_www/package-lock.json b/_www/package-lock.json new file mode 100644 index 0000000..c5093e1 --- /dev/null +++ b/_www/package-lock.json @@ -0,0 +1,598 @@ +{ + "name": "svelte-app", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", + "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", + "dev": true + }, + "@babel/highlight": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@polka/url": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz", + "integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==" + }, + "@rollup/plugin-commonjs": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-11.0.2.tgz", + "integrity": "sha512-MPYGZr0qdbV5zZj8/2AuomVpnRVXRU5XKXb3HVniwRoRCreGlf5kOE081isNWeiLIi6IYkwTX9zE0/c7V8g81g==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.0", + "estree-walker": "^1.0.1", + "is-reference": "^1.1.2", + "magic-string": "^0.25.2", + "resolve": "^1.11.0" + } + }, + "@rollup/plugin-node-resolve": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", + "integrity": "sha512-RxtSL3XmdTAE2byxekYLnx+98kEUOrPHF/KRVjLH+DEIHy6kjIw7YINQzn+NXiH/NTrQLAwYs0GWB+csWygA9Q==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.8", + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.14.2" + } + }, + "@rollup/pluginutils": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.10.tgz", + "integrity": "sha512-d44M7t+PjmMrASHbhgpSbVgtL6EFyX7J4mYxwQ/c5eoaE6N2VgCgEcWVzNnwycIloti+/MpwFr8qfw+nRw00sw==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/node": { + "version": "13.13.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.5.tgz", + "integrity": "sha512-3ySmiBYJPqgjiHA7oEaIo2Rzz0HrOZ7yrNO5HWyaE5q0lQ3BppDZ3N53Miz8bw2I7gh1/zir2MGVZBvpb1zq9g==", + "dev": true + }, + "@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "acorn": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz", + "integrity": "sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chokidar": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz", + "integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "console-clear": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/console-clear/-/console-clear-1.1.1.tgz", + "integrity": "sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=" + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-reference": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz", + "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==", + "dev": true, + "requires": { + "@types/estree": "0.0.39" + } + }, + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "livereload": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.1.tgz", + "integrity": "sha512-9g7sua11kkyZNo2hLRCG3LuZZwqexoyEyecSlV8cAsfAVVCZqLzVir6XDqmH0r+Vzgnd5LrdHDMyjtFnJQLAYw==", + "dev": true, + "requires": { + "chokidar": "^3.3.0", + "livereload-js": "^3.1.0", + "opts": ">= 1.2.0", + "ws": "^6.2.1" + } + }, + "livereload-js": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.2.2.tgz", + "integrity": "sha512-xhScbNeC687ZINjEf/bD+BMiPx4s4q0mehcLb3zCc8+mykOtmaBR4vqzyIV9rIGdG9JjHaT0LiFdscvivCjX1Q==", + "dev": true + }, + "local-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/local-access/-/local-access-1.0.1.tgz", + "integrity": "sha512-ykt2pgN0aqIy6KQC1CqdWTWkmUwNgaOS6dcpHVjyBJONA+Xi7AtSB1vuxC/U/0tjIP3wcRudwQk1YYzUvzk2bA==" + }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "mime": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz", + "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==" + }, + "mri": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.5.tgz", + "integrity": "sha512-d2RKzMD4JNyHMbnbWnznPaa8vbdlq/4pNZ3IgdaGrVbBhebBsGUUE/6qorTMYNS6TwuH3ilfOlD2bf4Igh8CKg==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "opts": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/opts/-/opts-1.2.7.tgz", + "integrity": "sha512-hwZhzGGG/GQ7igxAVFOEun2N4fWul31qE9nfBdCnZGQCB5+L7tN9xZ+94B4aUpLOJx/of3zZs5XsuubayQYQjA==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "readdirp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "rollup": { + "version": "1.32.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz", + "integrity": "sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/node": "*", + "acorn": "^7.1.0" + } + }, + "rollup-plugin-livereload": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-livereload/-/rollup-plugin-livereload-1.3.0.tgz", + "integrity": "sha512-abyqXaB21+nFHo+vJULBqfzNx6zXABC19UyvqgDfdoxR/8pFAd041GO+GIUe8ZYC2DbuMUmioh1Lvbk14YLZgw==", + "dev": true, + "requires": { + "livereload": "^0.9.1" + } + }, + "rollup-plugin-svelte": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-5.2.1.tgz", + "integrity": "sha512-wc93cN66sRpX6uFljVFqvWT6NU3V5ab/uLXKt2UiARuexFU/ctolzkmdXM7WM5iKdTX9scToS9sabJTJV4DUMA==", + "dev": true, + "requires": { + "require-relative": "^0.8.7", + "rollup-pluginutils": "^2.8.2", + "sourcemap-codec": "^1.4.8" + } + }, + "rollup-plugin-terser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.3.0.tgz", + "integrity": "sha512-XGMJihTIO3eIBsVGq7jiNYOdDMb3pVxuzY0uhOE/FM4x/u9nQgr3+McsjzqBn3QfHIpNSZmFnpoKAwHBEcsT7g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "jest-worker": "^24.9.0", + "rollup-pluginutils": "^2.8.2", + "serialize-javascript": "^2.1.2", + "terser": "^4.6.2" + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + } + } + }, + "sade": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.3.tgz", + "integrity": "sha512-m4BctppMvJ60W1dXnHq7jMmFe3hPJZDAH85kQ3ACTo7XZNVUuTItCQ+2HfyaMeV5cKrbw7l4vD/6We3GBxvdJw==", + "requires": { + "mri": "^1.1.0" + } + }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, + "sirv": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-0.4.2.tgz", + "integrity": "sha512-dQbZnsMaIiTQPZmbGmktz+c74zt/hyrJEB4tdp2Jj0RNv9J6B/OWR5RyrZEvIn9fyh9Zlg2OlE2XzKz6wMKGAw==", + "requires": { + "@polka/url": "^0.5.0", + "mime": "^2.3.1" + } + }, + "sirv-cli": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/sirv-cli/-/sirv-cli-0.4.5.tgz", + "integrity": "sha512-Fl6icSm0EwPrXSGid2xphMp//WNTSX2yENRAGnJuuZNmdc8LvE/BtdZD3MPn28ifAfDqTMwbB3dpcZojAIOiBg==", + "requires": { + "console-clear": "^1.1.0", + "get-port": "^3.2.0", + "kleur": "^3.0.0", + "local-access": "^1.0.1", + "sade": "^1.4.0", + "sirv": "^0.4.2", + "tinydate": "^1.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "svelte": { + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.22.2.tgz", + "integrity": "sha512-DxumO0+vvHA6NSc2jtVty08I8lFI43q8P2zX6JxZL8J1kqK5NVjad6TRM/twhnWXC+QScnwkZ15O6X1aTsEKTA==", + "dev": true + }, + "terser": { + "version": "4.6.13", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.13.tgz", + "integrity": "sha512-wMvqukYgVpQlymbnNbabVZbtM6PN63AzqexpwJL8tbh/mRT9LE5o+ruVduAGL7D6Fpjl+Q+06U5I9Ul82odAhw==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + } + }, + "tinydate": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.2.0.tgz", + "integrity": "sha512-3GwPk8VhDFnUZ2TrgkhXJs6hcMAIIw4x/xkz+ayK6dGoQmp2nUwKzBXK0WnMsqkh6vfUhpqQicQF3rbshfyJkg==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } +} diff --git a/_www/package.json b/_www/package.json new file mode 100644 index 0000000..267b670 --- /dev/null +++ b/_www/package.json @@ -0,0 +1,21 @@ +{ + "name": "svelte-app", + "version": "1.0.0", + "scripts": { + "build": "rollup -c", + "dev": "rollup -c -w", + "start": "sirv public" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "11.0.2", + "@rollup/plugin-node-resolve": "^7.0.0", + "rollup": "^1.20.0", + "rollup-plugin-livereload": "^1.0.0", + "rollup-plugin-svelte": "^5.0.3", + "rollup-plugin-terser": "^5.1.2", + "svelte": "^3.0.0" + }, + "dependencies": { + "sirv-cli": "^0.4.4" + } +} diff --git a/_www/public/favicon.png b/_www/public/favicon.png new file mode 100644 index 0000000..0a3c077 Binary files /dev/null and b/_www/public/favicon.png differ diff --git a/_www/public/global.css b/_www/public/global.css new file mode 100644 index 0000000..ec905f5 --- /dev/null +++ b/_www/public/global.css @@ -0,0 +1,66 @@ +html, body { + position: relative; + width: 100%; + height: 100%; +} + +body { + color: #333; + margin: 0; + padding: 8px; + box-sizing: border-box; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; +} + +a { + color: rgb(0,100,200); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +a:visited { + color: rgb(0,80,160); +} + +label { + display: block; +} + +input, button, select, textarea { + font-family: inherit; + font-size: inherit; + padding: 0.4em; + margin: 0 0 0.5em 0; + box-sizing: border-box; + border: 1px solid #ccc; + border-radius: 2px; +} + +input:disabled { + color: #ccc; +} + +input[type="range"] { + height: 0; +} + +button { + color: #333; + background-color: #f4f4f4; + outline: none; +} + +button:disabled { + color: #999; +} + +button:not(:disabled):active { + background-color: #ddd; +} + +button:focus { + border-color: #666; +} diff --git a/_www/public/index.html b/_www/public/index.html new file mode 100644 index 0000000..e8e6f92 --- /dev/null +++ b/_www/public/index.html @@ -0,0 +1,17 @@ + + + + + + + rescached + + + + + + + + + + diff --git a/_www/rollup.config.js b/_www/rollup.config.js new file mode 100644 index 0000000..ce3c9eb --- /dev/null +++ b/_www/rollup.config.js @@ -0,0 +1,71 @@ +import svelte from 'rollup-plugin-svelte'; +import resolve from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import livereload from 'rollup-plugin-livereload'; +import { terser } from 'rollup-plugin-terser'; + +const production = !process.env.ROLLUP_WATCH; + +export default { + input: 'src/main.js', + output: { + sourcemap: true, + format: 'iife', + name: 'app', + file: 'public/build/bundle.js' + }, + plugins: [ + svelte({ + // enable run-time checks when not in production + dev: !production, + // we'll extract any component CSS out into + // a separate file - better for performance + css: css => { + css.write('public/build/bundle.css'); + } + }), + + // If you have external dependencies installed from + // npm, you'll most likely need these plugins. In + // some cases you'll need additional configuration - + // consult the documentation for details: + // https://github.com/rollup/plugins/tree/master/packages/commonjs + resolve({ + browser: true, + dedupe: ['svelte'] + }), + commonjs(), + + // In dev mode, call `npm run start` once + // the bundle has been generated + !production && serve(), + + // Watch the `public` directory and refresh the + // browser on changes when not in production + !production && livereload('public'), + + // If we're building for production (npm run build + // instead of npm run dev), minify + production && terser() + ], + watch: { + clearScreen: false + } +}; + +function serve() { + let started = false; + + return { + writeBundle() { + if (!started) { + started = true; + + require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], { + stdio: ['ignore', 'inherit', 'inherit'], + shell: true + }); + } + } + }; +} diff --git a/_www/src/App.svelte b/_www/src/App.svelte new file mode 100644 index 0000000..3cde46c --- /dev/null +++ b/_www/src/App.svelte @@ -0,0 +1,53 @@ + + + + +
+

{name}

+ + + {#if state === 'environment'} + + {:else if state === 'hosts'} + {:else} +

+ Welcome to rescached! +

+ {/if} +
diff --git a/_www/src/Environment.svelte b/_www/src/Environment.svelte new file mode 100644 index 0000000..cab0c5f --- /dev/null +++ b/_www/src/Environment.svelte @@ -0,0 +1,248 @@ + + + + +
+

+ / Environment +

+ +

+This page allow you to change the rescached environment. +Upon save, the rescached service will be restarted. +

+ +

rescached

+
+ + + + + + +
+ +

DNS server

+
+ + {#each env.NameServers as ns} +
+ + +
+ {/each} + + + + + + + + + + + + + + + + + + + + +
+ + + Yes + +
+ + +
+ + + Yes + +
+ + + + + + +
+ +
+ +
+
diff --git a/_www/src/InputAddress.svelte b/_www/src/InputAddress.svelte new file mode 100644 index 0000000..014004a --- /dev/null +++ b/_www/src/InputAddress.svelte @@ -0,0 +1,48 @@ + + + + +
+ + {#if isInvalid} + {error} + {/if} +
diff --git a/_www/src/InputNumber.svelte b/_www/src/InputNumber.svelte new file mode 100644 index 0000000..6efee06 --- /dev/null +++ b/_www/src/InputNumber.svelte @@ -0,0 +1,35 @@ + + + + +
+ + {#if unit !== ''} + + {unit} + + {/if} +
diff --git a/_www/src/LabelHint.svelte b/_www/src/LabelHint.svelte new file mode 100644 index 0000000..72b2786 --- /dev/null +++ b/_www/src/LabelHint.svelte @@ -0,0 +1,46 @@ + + + + + +
+ {title}: + showInfo = !showInfo}> + ? + +
+{#if showInfo} +
{@html info}
+{/if} diff --git a/_www/src/main.js b/_www/src/main.js new file mode 100644 index 0000000..756243d --- /dev/null +++ b/_www/src/main.js @@ -0,0 +1,10 @@ +import App from "./App.svelte" + +const app = new App({ + target: document.body, + props: { + name: "rescached", + }, +}) + +export default app diff --git a/cmd/rescached/main.go b/cmd/rescached/main.go index 8d259f4..09f6e1d 100644 --- a/cmd/rescached/main.go +++ b/cmd/rescached/main.go @@ -33,9 +33,12 @@ func main() { log.Fatal(err) } - go run(rcd) + err = rcd.Start() + if err != nil { + log.Fatal(err) + } - if debug.Value >= 2 { + if debug.Value >= 3 { go debugRuntime() } @@ -60,17 +63,3 @@ func debugRuntime() { memHeap.DiffHeapObjects) } } - -func run(rcd *rescached.Server) { - defer func() { - err := recover() - if err != nil { - log.Println("panic: ", err) - } - }() - - err := rcd.Start() - if err != nil { - log.Println(err) - } -} diff --git a/cmd/rescached/rescached.cfg b/cmd/rescached/rescached.cfg index 9f403b0..0df343b 100644 --- a/cmd/rescached/rescached.cfg +++ b/cmd/rescached/rescached.cfg @@ -5,28 +5,34 @@ ## [rescached] -#dir.hosts=/etc/rescached/hosts.d -#dir.master=/etc/rescached/master.d -#file.resolvconf=/etc/rescached/resolv.conf -#debug=0 +dir.hosts= +dir.master= +file.resolvconf= +debug=0 [dns "server"] #parent=udp://18.136.35.199 #parent=tcp://18.136.35.199 -parent=https://kilabit.info/dns-query listen = 127.0.0.1:53 ## Uncomment line below if you want to serve DNS to other computers. #listen = 0.0.0.0:53 #http.port = 443 +http.port = 0 + #tls.port = 853 +tls.port = 0 + +#tls.certificate = /etc/rescached/localhost.cert.pem +tls.certificate = -#tls.certificate = /etc/rescached/localhost.cert.pem -#tls.private_key = /etc/rescached/localhost.key.pem -#tls.allow_insecure = false +#tls.private_key = /etc/rescached/localhost.key.pem +tls.private_key = -#doh.behind_proxy = false +tls.allow_insecure = false +doh.behind_proxy = false -#cache.prune_delay = 1h -#cache.prune_threshold = -1h +cache.prune_delay = 1h0m0s +cache.prune_threshold = -1h0m0s +parent = https://kilabit.info/dns-query diff --git a/go.mod b/go.mod index 529f86e..3945da1 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,6 @@ module github.com/shuLhan/rescached-go/v3 go 1.13 -require github.com/shuLhan/share v0.15.0 +require github.com/shuLhan/share v0.15.1-0.20200516135503-9e0bd9a6fefc //replace github.com/shuLhan/share => ../share diff --git a/go.sum b/go.sum index 7e77a65..5e3ab57 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/shuLhan/share v0.15.0 h1:VxLmHI426yYSJg8tMKSc9HmhQcF0L8O0Tr3ixtgzUYY= -github.com/shuLhan/share v0.15.0/go.mod h1:mpa0ub5qmuko/muUlOROOqLCSHKU76GzuAR/sUaSwRo= +github.com/shuLhan/share v0.15.1-0.20200516135503-9e0bd9a6fefc h1:DqO6rIUITvdYjT/T/357cnZohfdWMyhjLfLBD3FeVPY= +github.com/shuLhan/share v0.15.1-0.20200516135503-9e0bd9a6fefc/go.mod h1:mpa0ub5qmuko/muUlOROOqLCSHKU76GzuAR/sUaSwRo= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= diff --git a/internal/generate_memfs.go b/internal/generate_memfs.go new file mode 100644 index 0000000..552b924 --- /dev/null +++ b/internal/generate_memfs.go @@ -0,0 +1,31 @@ +// Copyright 2020, Shulhan . All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package main + +import ( + "log" + + "github.com/shuLhan/share/lib/memfs" +) + +func main() { + includes := []string{ + `.*\.html`, + `.*\.js`, + `.*\.css`, + } + + mfs, err := memfs.New("_www/public/", includes, nil, true) + if err != nil { + log.Fatal(err) + } + + err = mfs.GoGenerate("main", "cmd/rescached/memfs.go", memfs.EncodingGzip) + if err != nil { + log.Fatal(err) + } +} diff --git a/options.go b/options.go index ae9cf6f..93fb499 100644 --- a/options.go +++ b/options.go @@ -8,6 +8,7 @@ import ( "fmt" "io/ioutil" "log" + "strconv" "github.com/shuLhan/share/lib/debug" "github.com/shuLhan/share/lib/dns" @@ -16,11 +17,37 @@ import ( libstrings "github.com/shuLhan/share/lib/strings" ) +const ( + defWuiAddress = "127.0.0.1:5380" +) + +const ( + sectionNameDNS = "dns" + sectionNameRescached = "rescached" + + subNameServer = "server" + + keyDebug = "debug" + keyFileResolvConf = "file.resolvconf" + + keyCachePruneDelay = "cache.prune_delay" + keyCachePruneThreshold = "cache.prune_threshold" + keyDohBehindProxy = "doh.behind_proxy" + keyHTTPPort = "http.port" + keyListen = "listen" + keyParent = "parent" + keyTLSAllowInsecure = "tls.allow_insecure" + keyTLSCertificate = "tls.certificate" + keyTLSPort = "tls.port" + keyTLSPrivateKey = "tls.private_key" +) + // // Options for running rescached. // type Options struct { dns.ServerOptions + WuiListen string `ini:"rescached::wui.listen"` DirHosts string `ini:"rescached::dir.hosts"` DirMaster string `ini:"rescached::dir.master"` FileResolvConf string `ini:"rescached::file.resolvconf"` @@ -43,7 +70,7 @@ func loadOptions(file string) (opts *Options) { err = ini.Unmarshal(cfg, opts) if err != nil { - log.Println("rescached: loadOptions %q: %s", file, err) + log.Printf("rescached: loadOptions %q: %s", file, err) return opts } @@ -68,6 +95,9 @@ func NewOptions() *Options { // init check and initialize the Options instance with default values. // func (opts *Options) init() { + if len(opts.WuiListen) == 0 { + opts.WuiListen = defWuiAddress + } if len(opts.ListenAddress) == 0 { opts.ListenAddress = "127.0.0.1:53" } @@ -106,3 +136,45 @@ func (opts *Options) loadResolvConf() (ok bool, err error) { return true, nil } + +// +// write the options values back to file. +// +func (opts *Options) write(file string) (err error) { + in, err := ini.Open(file) + if err != nil { + return fmt.Errorf("write: %w", err) + } + + in.Set(sectionNameRescached, "", keyFileResolvConf, opts.FileResolvConf) + in.Set(sectionNameRescached, "", keyDebug, strconv.Itoa(opts.Debug)) + + in.UnsetAll(sectionNameDNS, subNameServer, keyParent) + for _, ns := range opts.NameServers { + in.Add(sectionNameDNS, subNameServer, keyParent, ns) + } + + in.Set(sectionNameDNS, subNameServer, keyListen, + opts.ServerOptions.ListenAddress) + + in.Set(sectionNameDNS, subNameServer, keyHTTPPort, + strconv.Itoa(int(opts.ServerOptions.HTTPPort))) + + in.Set(sectionNameDNS, subNameServer, keyTLSPort, + strconv.Itoa(int(opts.ServerOptions.TLSPort))) + in.Set(sectionNameDNS, subNameServer, keyTLSCertificate, + opts.ServerOptions.TLSCertFile) + in.Set(sectionNameDNS, subNameServer, keyTLSPrivateKey, + opts.ServerOptions.TLSPrivateKey) + in.Set(sectionNameDNS, subNameServer, keyTLSAllowInsecure, + fmt.Sprintf("%t", opts.ServerOptions.TLSAllowInsecure)) + in.Set(sectionNameDNS, subNameServer, keyDohBehindProxy, + fmt.Sprintf("%t", opts.ServerOptions.DoHBehindProxy)) + + in.Set(sectionNameDNS, subNameServer, keyCachePruneDelay, + fmt.Sprintf("%s", opts.ServerOptions.PruneDelay)) + in.Set(sectionNameDNS, subNameServer, keyCachePruneThreshold, + fmt.Sprintf("%s", opts.ServerOptions.PruneThreshold)) + + return in.Save(file) +} diff --git a/rescached.go b/rescached.go index ccb2e39..74fc949 100644 --- a/rescached.go +++ b/rescached.go @@ -8,9 +8,11 @@ package rescached import ( "fmt" "log" + "sync" "github.com/shuLhan/share/lib/debug" "github.com/shuLhan/share/lib/dns" + "github.com/shuLhan/share/lib/http" libio "github.com/shuLhan/share/lib/io" ) @@ -20,6 +22,9 @@ type Server struct { dns *dns.Server opts *Options rcWatcher *libio.Watcher + + httpd *http.Server + httpdRunner sync.Once } // @@ -32,21 +37,16 @@ func New(fileConfig string) (srv *Server, err error) { fmt.Printf("rescached: config: %+v\n", opts) } - dnsServer, err := dns.NewServer(&opts.ServerOptions) - if err != nil { - return nil, err - } - - dnsServer.LoadHostsDir(opts.DirHosts) - dnsServer.LoadMasterDir(opts.DirMaster) - dnsServer.LoadHostsFile("") - srv = &Server{ fileConfig: fileConfig, - dns: dnsServer, opts: opts, } + err = srv.httpdInit() + if err != nil { + return nil, err + } + return srv, nil } @@ -55,6 +55,15 @@ func New(fileConfig string) (srv *Server, err error) { // it. // func (srv *Server) Start() (err error) { + srv.dns, err = dns.NewServer(&srv.opts.ServerOptions) + if err != nil { + return err + } + + srv.dns.LoadHostsDir(srv.opts.DirHosts) + srv.dns.LoadMasterDir(srv.opts.DirMaster) + srv.dns.LoadHostsFile("") + if len(srv.opts.FileResolvConf) > 0 { srv.rcWatcher, err = libio.NewWatcher( srv.opts.FileResolvConf, 0, srv.watchResolvConf) @@ -63,7 +72,27 @@ func (srv *Server) Start() (err error) { } } - return srv.dns.ListenAndServe() + go func() { + srv.httpdRunner.Do(srv.httpdRun) + }() + + go srv.run() + + return nil +} + +func (srv *Server) run() { + defer func() { + err := recover() + if err != nil { + log.Println("panic: ", err) + } + }() + + err := srv.dns.ListenAndServe() + if err != nil { + log.Println(err) + } } // diff --git a/rescached_httpd.go b/rescached_httpd.go new file mode 100644 index 0000000..4ded760 --- /dev/null +++ b/rescached_httpd.go @@ -0,0 +1,144 @@ +// Copyright 2020, Shulhan . All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rescached + +import ( + "encoding/json" + "fmt" + "log" + stdhttp "net/http" + + liberrors "github.com/shuLhan/share/lib/errors" + "github.com/shuLhan/share/lib/http" +) + +const ( + defHTTPDRootDir = "_www/public/" +) + +func (srv *Server) httpdInit() (err error) { + opts := &http.ServerOptions{ + Root: defHTTPDRootDir, + Address: srv.opts.WuiListen, + Includes: []string{ + `.*\.css`, + `.*\.html`, + `.*\.js`, + }, + CORSAllowOrigins: []string{ + "http://127.0.0.1:5000", + }, + CORSAllowHeaders: []string{ + http.HeaderContentType, + }, + } + + srv.httpd, err = http.NewServer(opts) + if err != nil { + return fmt.Errorf("newHTTPServer: %w", err) + } + + err = srv.httpdRegisterEndpoints() + if err != nil { + return fmt.Errorf("newHTTPServer: %w", err) + } + + return nil +} + +func (srv *Server) httpdRegisterEndpoints() (err error) { + epAPIGetEnvironment := &http.Endpoint{ + Method: http.RequestMethodGet, + Path: "/api/environment", + RequestType: http.RequestTypeJSON, + ResponseType: http.ResponseTypeJSON, + Call: srv.httpdAPIGetEnvironment, + } + + err = srv.httpd.RegisterEndpoint(epAPIGetEnvironment) + if err != nil { + return err + } + + epAPIPostEnvironment := &http.Endpoint{ + Method: http.RequestMethodPost, + Path: "/api/environment", + RequestType: http.RequestTypeJSON, + ResponseType: http.ResponseTypeJSON, + Call: srv.httpdAPIPostEnvironment, + } + + err = srv.httpd.RegisterEndpoint(epAPIPostEnvironment) + if err != nil { + return err + } + + return nil +} + +func (srv *Server) httpdRun() { + defer func() { + err := recover() + if err != nil { + log.Printf("httpServer: %s", err) + } + }() + + log.Printf("=== rescached: httpd listening at %s", srv.opts.WuiListen) + + err := srv.httpd.Start() + if err != nil { + log.Printf("httpServer.run: %s", err) + } +} + +func (srv *Server) httpdAPIGetEnvironment( + httpRes stdhttp.ResponseWriter, req *stdhttp.Request, reqBody []byte, +) ( + resBody []byte, err error, +) { + return json.Marshal(srv.opts) +} + +func (srv *Server) httpdAPIPostEnvironment( + httpRes stdhttp.ResponseWriter, req *stdhttp.Request, reqBody []byte, +) ( + resBody []byte, err error, +) { + newOpts := new(Options) + err = json.Unmarshal(reqBody, newOpts) + if err != nil { + return nil, err + } + + newOpts.init() + + fmt.Printf("new options: %+v\n", newOpts) + + res := &liberrors.E{ + Code: stdhttp.StatusOK, + Message: "Restarting DNS server", + } + + err = newOpts.write(srv.fileConfig) + if err != nil { + log.Println("httpdAPIPostEnvironment:", err.Error()) + res.Code = stdhttp.StatusInternalServerError + res.Message = err.Error() + return json.Marshal(res) + } + + srv.opts = newOpts + + srv.Stop() + err = srv.Start() + if err != nil { + log.Println("httpdAPIPostEnvironment:", err.Error()) + res.Code = stdhttp.StatusInternalServerError + res.Message = err.Error() + } + + return json.Marshal(res) +} -- cgit v1.3-5-g45d5