[chore] Fix grammar, add JSDocs
| @@ -4,17 +4,21 @@ dataRoot: ./data | |||
| 4 | # -- SERVER CONFIGURATION -- | 4 | # -- SERVER CONFIGURATION -- |
| 5 | # Listen for incoming connections | 5 | # Listen for incoming connections |
| 6 | listen: false | 6 | listen: false |
| 7 | # Enables IPv6 and/or IPv4 | 7 | # Enables IPv6 and/or IPv4 protocols. Need to have at least one enabled! |
| 8 | protocol: | 8 | protocol: |
| 9 | ipv4: true | 9 | ipv4: true |
| 10 | ipv6: false | 10 | ipv6: false |
| 11 | # Prefers IPv6 for dns, you should probably enable this on ISPs that don't have issues with IPv6 | 11 | # Prefers IPv6 for DNS. Enable this on ISPs that don't have issues with IPv6 |
| 12 | dnsPreferIPv6: false | 12 | dnsPreferIPv6: false |
| 13 | # the hostname that autorun opens probably best left on auto. use options like 'localhost', 'st.example.com' | 13 | # The hostname that autorun opens. |
| 14 | # - Use "auto" to let the server decide | ||
| 15 | # - Use options like 'localhost', 'st.example.com' | ||
| 14 | autorunHostname: "auto" | 16 | autorunHostname: "auto" |
| 15 | # Server port | 17 | # Server port |
| 16 | port: 8000 | 18 | port: 8000 |
| 17 | # overrides the port for autorun with open your browser with this port and ignore what port the server is running on. -1 is use server port | 19 | # Overrides the port for autorun in browser. |
| 20 | # - Use -1 to use the server port. | ||
| 21 | # - Specify a port to override the default. | ||
| 18 | autorunPortOverride: -1 | 22 | autorunPortOverride: -1 |
| 19 | # -- SECURITY CONFIGURATION -- | 23 | # -- SECURITY CONFIGURATION -- |
| 20 | # Toggle whitelist mode | 24 | # Toggle whitelist mode |
| @@ -43,6 +43,8 @@ const { | |||
| 43 | getConfigValue, | 43 | getConfigValue, |
| 44 | color, | 44 | color, |
| 45 | forwardFetchResponse, | 45 | forwardFetchResponse, |
| 46 | removeColorFormatting, | ||
| 47 | getSeparator, | ||
| 46 | } = require('./src/util'); | 48 | } = require('./src/util'); |
| 47 | const { ensureThumbnailCache } = require('./src/endpoints/thumbnails'); | 49 | const { ensureThumbnailCache } = require('./src/endpoints/thumbnails'); |
| 48 | 50 | ||
| @@ -54,10 +56,6 @@ if (process.versions && process.versions.node && process.versions.node.match(/20 | |||
| 54 | if (net.setDefaultAutoSelectFamily) net.setDefaultAutoSelectFamily(false); | 56 | if (net.setDefaultAutoSelectFamily) net.setDefaultAutoSelectFamily(false); |
| 55 | } | 57 | } |
| 56 | 58 | ||
| 57 | |||
| 58 | |||
| 59 | |||
| 60 | |||
| 61 | const DEFAULT_PORT = 8000; | 59 | const DEFAULT_PORT = 8000; |
| 62 | const DEFAULT_AUTORUN = false; | 60 | const DEFAULT_AUTORUN = false; |
| 63 | const DEFAULT_LISTEN = false; | 61 | const DEFAULT_LISTEN = false; |
| @@ -618,7 +616,6 @@ const tavernUrl = new URL( | |||
| 618 | (':' + server_port), | 616 | (':' + server_port), |
| 619 | ); | 617 | ); |
| 620 | 618 | ||
| 621 | |||
| 622 | /** | 619 | /** |
| 623 | * Tasks that need to be run before the server starts listening. | 620 | * Tasks that need to be run before the server starts listening. |
| 624 | */ | 621 | */ |
| @@ -667,19 +664,11 @@ const preSetupTasks = async function () { | |||
| 667 | }); | 664 | }); |
| 668 | }; | 665 | }; |
| 669 | 666 | ||
| 670 | function removeColorFormatting(text) { | 667 | /** |
| 671 | // ANSI escape codes for colors are usually in the format \x1b[<codes>m | 668 | * Gets the hostname to use for autorun in the browser. |
| 672 | return text.replace(/\x1b\[\d{1,2}(;\d{1,2})*m/g, ''); | 669 | * @returns {string} The hostname to use for autorun |
| 673 | } | 670 | */ |
| 674 | |||
| 675 | function getSeparator(n) { | ||
| 676 | return '='.repeat(n); | ||
| 677 | } | ||
| 678 | |||
| 679 | |||
| 680 | |||
| 681 | function getAutorunHostname() { | 671 | function getAutorunHostname() { |
| 682 | |||
| 683 | if (autorunHostname === 'auto') { | 672 | if (autorunHostname === 'auto') { |
| 684 | if (enableIPv6 && enableIPv4) { | 673 | if (enableIPv6 && enableIPv4) { |
| 685 | if (avoidLocalhost) return '[::1]'; | 674 | if (avoidLocalhost) return '[::1]'; |
| @@ -698,13 +687,12 @@ function getAutorunHostname() { | |||
| 698 | return autorunHostname; | 687 | return autorunHostname; |
| 699 | } | 688 | } |
| 700 | 689 | ||
| 701 | |||
| 702 | /** | 690 | /** |
| 703 | * Tasks that need to be run after the server starts listening. | 691 | * Tasks that need to be run after the server starts listening. |
| 692 | * @param {boolean} v6Failed If the server failed to start on IPv6 | ||
| 693 | * @param {boolean} v4Failed If the server failed to start on IPv4 | ||
| 704 | */ | 694 | */ |
| 705 | const postSetupTasks = async function (v6Failed, v4Failed) { | 695 | const postSetupTasks = async function (v6Failed, v4Failed) { |
| 706 | |||
| 707 | |||
| 708 | const autorunUrl = new URL( | 696 | const autorunUrl = new URL( |
| 709 | (cliArguments.ssl ? 'https://' : 'http://') + | 697 | (cliArguments.ssl ? 'https://' : 'http://') + |
| 710 | (getAutorunHostname()) + | 698 | (getAutorunHostname()) + |
| @@ -712,30 +700,24 @@ const postSetupTasks = async function (v6Failed, v4Failed) { | |||
| 712 | ((autorunPortOverride >= 0) ? autorunPortOverride : server_port), | 700 | ((autorunPortOverride >= 0) ? autorunPortOverride : server_port), |
| 713 | ); | 701 | ); |
| 714 | 702 | ||
| 715 | |||
| 716 | console.log('Launching...'); | 703 | console.log('Launching...'); |
| 717 | 704 | ||
| 718 | if (autorun) open(autorunUrl.toString()); | 705 | if (autorun) open(autorunUrl.toString()); |
| 719 | 706 | ||
| 720 | setWindowTitle('SillyTavern WebServer'); | 707 | setWindowTitle('SillyTavern WebServer'); |
| 721 | 708 | ||
| 722 | |||
| 723 | let ipv6Color = color.green; | ||
| 724 | let ipv4Color = color.green; | ||
| 725 | let autorunColor = color.blue; | ||
| 726 | |||
| 727 | let logListen = 'SillyTavern is listening on'; | 709 | let logListen = 'SillyTavern is listening on'; |
| 728 | 710 | ||
| 729 | if (enableIPv6 && !v6Failed) { | 711 | if (enableIPv6 && !v6Failed) { |
| 730 | logListen += ipv6Color(' IPv6: ' + tavernUrlV6.host); | 712 | logListen += color.green(' IPv6: ' + tavernUrlV6.host); |
| 731 | } | 713 | } |
| 732 | 714 | ||
| 733 | if (enableIPv4 && !v4Failed) { | 715 | if (enableIPv4 && !v4Failed) { |
| 734 | logListen += ipv4Color(' IPv4: ' + tavernUrl.host); | 716 | logListen += color.green(' IPv4: ' + tavernUrl.host); |
| 735 | } | 717 | } |
| 736 | 718 | ||
| 737 | let goToLog = 'Go to: ' + autorunColor(autorunUrl) + ' to open SillyTavern'; | 719 | const goToLog = 'Go to: ' + color.blue(autorunUrl) + ' to open SillyTavern'; |
| 738 | let plainGoToLog = removeColorFormatting(goToLog); | 720 | const plainGoToLog = removeColorFormatting(goToLog); |
| 739 | 721 | ||
| 740 | console.log(logListen); | 722 | console.log(logListen); |
| 741 | console.log('\n' + getSeparator(plainGoToLog.length) + '\n'); | 723 | console.log('\n' + getSeparator(plainGoToLog.length) + '\n'); |
| @@ -798,8 +780,11 @@ function logSecurityAlert(message) { | |||
| 798 | process.exit(1); | 780 | process.exit(1); |
| 799 | } | 781 | } |
| 800 | 782 | ||
| 801 | 783 | /** | |
| 802 | 784 | * Handles the case where the server failed to start on one or both protocols. | |
| 785 | * @param {boolean} v6Failed If the server failed to start on IPv6 | ||
| 786 | * @param {boolean} v4Failed If the server failed to start on IPv4 | ||
| 787 | */ | ||
| 803 | function handleServerListenFail(v6Failed, v4Failed) { | 788 | function handleServerListenFail(v6Failed, v4Failed) { |
| 804 | if (v6Failed && !enableIPv4) { | 789 | if (v6Failed && !enableIPv4) { |
| 805 | console.error('fatal error: Failed to start server on IPv6 and IPv4 disabled'); | 790 | console.error('fatal error: Failed to start server on IPv6 and IPv4 disabled'); |
| @@ -817,7 +802,12 @@ function handleServerListenFail(v6Failed, v4Failed) { | |||
| 817 | } | 802 | } |
| 818 | } | 803 | } |
| 819 | 804 | ||
| 820 | 805 | /** | |
| 806 | * Creates an HTTPS server. | ||
| 807 | * @param {URL} url The URL to listen on | ||
| 808 | * @returns {Promise<void>} A promise that resolves when the server is listening | ||
| 809 | * @throws {Error} If the server fails to start | ||
| 810 | */ | ||
| 821 | function createHttpsServer(url) { | 811 | function createHttpsServer(url) { |
| 822 | return new Promise((resolve, reject) => { | 812 | return new Promise((resolve, reject) => { |
| 823 | const server = https.createServer( | 813 | const server = https.createServer( |
| @@ -831,6 +821,12 @@ function createHttpsServer(url) { | |||
| 831 | }); | 821 | }); |
| 832 | } | 822 | } |
| 833 | 823 | ||
| 824 | /** | ||
| 825 | * Creates an HTTP server. | ||
| 826 | * @param {URL} url The URL to listen on | ||
| 827 | * @returns {Promise<void>} A promise that resolves when the server is listening | ||
| 828 | * @throws {Error} If the server fails to start | ||
| 829 | */ | ||
| 834 | function createHttpServer(url) { | 830 | function createHttpServer(url) { |
| 835 | return new Promise((resolve, reject) => { | 831 | return new Promise((resolve, reject) => { |
| 836 | const server = http.createServer(app); | 832 | const server = http.createServer(app); |
| @@ -840,17 +836,11 @@ function createHttpServer(url) { | |||
| 840 | }); | 836 | }); |
| 841 | } | 837 | } |
| 842 | 838 | ||
| 843 | |||
| 844 | |||
| 845 | |||
| 846 | async function startHTTPorHTTPS() { | 839 | async function startHTTPorHTTPS() { |
| 847 | let v6Failed = false; | 840 | let v6Failed = false; |
| 848 | let v4Failed = false; | 841 | let v4Failed = false; |
| 849 | 842 | ||
| 850 | let createFunc = createHttpServer; | 843 | const createFunc = cliArguments.ssl ? createHttpsServer : createHttpServer; |
| 851 | if (cliArguments.ssl) { | ||
| 852 | createFunc = createHttpsServer; | ||
| 853 | } | ||
| 854 | 844 | ||
| 855 | if (enableIPv6) { | 845 | if (enableIPv6) { |
| 856 | try { | 846 | try { |
| @@ -875,25 +865,17 @@ async function startHTTPorHTTPS() { | |||
| 875 | v4Failed = true; | 865 | v4Failed = true; |
| 876 | } | 866 | } |
| 877 | } | 867 | } |
| 868 | |||
| 878 | return [v6Failed, v4Failed]; | 869 | return [v6Failed, v4Failed]; |
| 879 | } | 870 | } |
| 880 | 871 | ||
| 881 | |||
| 882 | |||
| 883 | |||
| 884 | async function startServer() { | 872 | async function startServer() { |
| 885 | let v6Failed = false; | 873 | const [v6Failed, v4Failed] = await startHTTPorHTTPS(); |
| 886 | let v4Failed = false; | ||
| 887 | |||
| 888 | |||
| 889 | [v6Failed, v4Failed] = await startHTTPorHTTPS(); | ||
| 890 | 874 | ||
| 891 | handleServerListenFail(v6Failed, v4Failed); | 875 | handleServerListenFail(v6Failed, v4Failed); |
| 892 | postSetupTasks(v6Failed, v4Failed); | 876 | postSetupTasks(v6Failed, v4Failed); |
| 893 | } | 877 | } |
| 894 | 878 | ||
| 895 | |||
| 896 | |||
| 897 | async function verifySecuritySettings() { | 879 | async function verifySecuritySettings() { |
| 898 | // Skip all security checks as listen is set to false | 880 | // Skip all security checks as listen is set to false |
| 899 | if (!listen) { | 881 | if (!listen) { |
| @@ -627,6 +627,25 @@ class Cache { | |||
| 627 | } | 627 | } |
| 628 | } | 628 | } |
| 629 | 629 | ||
| 630 | /** | ||
| 631 | * Removes color formatting from a text string. | ||
| 632 | * @param {string} text Text with color formatting | ||
| 633 | * @returns {string} Text without color formatting | ||
| 634 | */ | ||
| 635 | function removeColorFormatting(text) { | ||
| 636 | // ANSI escape codes for colors are usually in the format \x1b[<codes>m | ||
| 637 | return text.replace(/\x1b\[\d{1,2}(;\d{1,2})*m/g, ''); | ||
| 638 | } | ||
| 639 | |||
| 640 | /** | ||
| 641 | * Gets a separator string repeated n times. | ||
| 642 | * @param {number} n Number of times to repeat the separator | ||
| 643 | * @returns {string} Separator string | ||
| 644 | */ | ||
| 645 | function getSeparator(n) { | ||
| 646 | return '='.repeat(n); | ||
| 647 | } | ||
| 648 | |||
| 630 | module.exports = { | 649 | module.exports = { |
| 631 | getConfig, | 650 | getConfig, |
| 632 | getConfigValue, | 651 | getConfigValue, |
| @@ -654,4 +673,6 @@ module.exports = { | |||
| 654 | trimV1, | 673 | trimV1, |
| 655 | Cache, | 674 | Cache, |
| 656 | makeHttp2Request, | 675 | makeHttp2Request, |
| 676 | removeColorFormatting, | ||
| 677 | getSeparator, | ||
| 657 | }; | 678 | }; |