Selaa lähdekoodia

refactor: nginx conf parser #45

0xJacky 2 vuotta sitten
vanhempi
commit
5cc9068f5f

+ 9 - 5
README-zh_CN.md

@@ -91,12 +91,16 @@ Nginx 网络管理界面,由  [0xJacky](https://jackyu.cn/) 与 [Hintay](https
 我们欢迎您将项目翻译成任何语言。
 
 ### 构建基于
-
-- [The Go Programming Language](https://go.dev/)
+- [The Go Programming Language](https://go.dev)
 - [Gin Web Framework](https://gin-gonic.com)
-- [GORM](http://gorm.io/index.html)
-- [Vue 2](https://vuejs.org)
-- [vue-gettext](https://github.com/Polyconseil/vue-gettext)
+- [GORM](http://gorm.io)
+- [Vue 3](https://v3.vuejs.org)
+- [Vite](https://vitejs.dev)
+- [TypeScript](https://www.typescriptlang.org/)
+- [Ant Design Vue](https://antdv.com)
+- [vue3-gettext](https://github.com/jshmrtn/vue3-gettext)
+- [vue3-ace-editor](https://github.com/CarterLi/vue3-ace-editor)
+- [Gonginx](https://github.com/tufanbarisyildirim/gonginx)
 
 ## 入门指南
 

+ 9 - 5
README-zh_TW.md

@@ -93,12 +93,16 @@ Nginx 網路管理介面,由  [0xJacky](https://jackyu.cn/) 與 [Hintay](https
 我們歡迎您將專案翻譯成任何語言。
 
 ### 構建基於
-
-- [The Go Programming Language](https://go.dev/)
+- [The Go Programming Language](https://go.dev)
 - [Gin Web Framework](https://gin-gonic.com)
-- [GORM](http://gorm.io/index.html)
-- [Vue 2](https://vuejs.org)
-- [vue-gettext](https://github.com/Polyconseil/vue-gettext)
+- [GORM](http://gorm.io)
+- [Vue 3](https://v3.vuejs.org)
+- [Vite](https://vitejs.dev)
+- [TypeScript](https://www.typescriptlang.org/)
+- [Ant Design Vue](https://antdv.com)
+- [vue3-gettext](https://github.com/jshmrtn/vue3-gettext)
+- [vue3-ace-editor](https://github.com/CarterLi/vue3-ace-editor)
+- [Gonginx](https://github.com/tufanbarisyildirim/gonginx)
 
 ## 入門指南
 

+ 1 - 0
README.md

@@ -99,6 +99,7 @@ We welcome translations into any language.
 - [Ant Design Vue](https://antdv.com)
 - [vue3-gettext](https://github.com/jshmrtn/vue3-gettext)
 - [vue3-ace-editor](https://github.com/CarterLi/vue3-ace-editor)
+- [Gonginx](https://github.com/tufanbarisyildirim/gonginx)
 
 ## Getting Started
 

+ 1 - 1
frontend/package.json

@@ -39,7 +39,7 @@
         "less": "^4.1.3",
         "typescript": "^4.6.4",
         "unplugin-vue-components": "^0.22.9",
-        "vite": "^3.2.3",
+        "vite": "^4.0.3",
         "vite-plugin-html": "^3.2.0",
         "vue-tsc": "^1.0.9"
     }

+ 0 - 10
frontend/src/routes/index.ts

@@ -74,16 +74,6 @@ export const routes = [
                     hideChildren: true
                 }
             },
-            {
-                path: 'config/:dir*',
-                name: () => $gettext('Manage Configs'),
-                component: () => import('@/views/config/Config.vue'),
-                meta: {
-                    icon: FileOutlined,
-                    hideChildren: true,
-                    hiddenInSidebar: true
-                }
-            },
             {
                 path: 'config/:name+/edit',
                 name: () => $gettext('Edit Configuration'),

+ 4 - 2
frontend/src/views/config/Config.vue

@@ -18,7 +18,7 @@ const table = ref(null)
 const route = useRoute()
 
 const basePath = computed(() => {
-    let dir = route?.params?.dir ? (route?.params?.dir as string[])?.join('/') : ''
+    let dir = route?.query?.dir ?? ''
     if (dir) dir += '/'
     return dir
 })
@@ -54,7 +54,9 @@ watch(get_params, () => {
                     })
                 } else {
                     $router.push({
-                        path: '/config/' + basePath + r
+                        query: {
+                            dir: basePath + r
+                        }
                     })
                 }
             }"

+ 1 - 1
frontend/src/views/domain/DomainList.vue

@@ -30,7 +30,7 @@ const columns = [{
             template.push(<Badge status="success"/>)
             template.push($gettext('Enabled'))
         } else {
-            template.push(<Badge status="error"/>)
+            template.push(<Badge status="warning"/>)
             template.push($gettext('Disabled'))
         }
         return h('div', template)

+ 1 - 1
frontend/src/views/domain/cert/IssueCert.vue

@@ -129,7 +129,7 @@ const issue_cert = async (server_name: string, callback: Function) => {
 }
 
 const no_server_name = computed(() => {
-    return props.directivesMap['server_name'].length === 0
+    return props.directivesMap['server_name']?.length === 0
 })
 
 const name = computed(() => {

+ 9 - 7
frontend/src/views/domain/ngx_conf/directive/DirectiveAdd.vue

@@ -24,8 +24,8 @@ function add() {
 
 function save() {
     adding.value = false
-    if (mode.value === If) {
-        directive.directive = If
+    if (mode.value === 'multi-line') {
+        directive.directive = ''
     }
 
     if (props.idx) {
@@ -42,19 +42,19 @@ function save() {
     <div>
         <div class="add-directive-temp" v-if="adding">
             <a-form-item>
-                <a-select v-model:value="mode" default-value="default" style="width: 150px">
+                <a-select v-model:value="mode" default-value="default" style="width: 180px">
                     <a-select-option value="default">
                         {{ $gettext('Single Directive') }}
                     </a-select-option>
-                    <a-select-option value="if">
-                        if
+                    <a-select-option value="multi-line">
+                        {{ $gettext('Multi-line Directive') }}
                     </a-select-option>
                 </a-select>
             </a-form-item>
             <a-form-item>
 
                 <div class="input-wrapper">
-                    <code-editor v-if="mode===If" default-height="100px" style="width: 100%;"
+                    <code-editor v-if="mode==='multi-line'" default-height="100px" style="width: 100%;"
                                  v-model:content="directive.params"/>
                     <a-input-group v-else compact>
                         <a-input style="width: 30%" :placeholder="$gettext('Directive')"
@@ -73,7 +73,9 @@ function save() {
         </div>
         <a-button block v-if="!adding" @click="add">{{ $gettext('Add Directive Below') }}</a-button>
         <a-button type="primary" v-else block @click="save"
-                  :disabled="!directive.directive||!directive.params">{{ $gettext('Save Directive') }}
+                  :disabled="(mode==='default'&&(!directive.directive||!directive.params))
+                  ||(!directive.params&&mode==='multi-line')">
+            {{ $gettext('Save Directive') }}
         </a-button>
     </div>
 </template>

+ 1 - 1
frontend/src/views/domain/ngx_conf/directive/DirectiveEditor.vue

@@ -32,7 +32,7 @@ function onSave(idx: number) {
         item-key="name"
         class="list-group"
         ghost-class="ghost"
-        handle=".ant-input-group-addon"
+        handle=".anticon-holder"
     >
         <template #item="{ element: directive, index }">
             <directive-editor-item @click="current_idx=index"

+ 15 - 2
frontend/src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue

@@ -42,8 +42,11 @@ function save() {
 <template>
     <div class="dir-editor-item">
         <div class="input-wrapper">
-            <code-editor v-if="directive.directive === If" v-model:content="directive.params"
-                         defaultHeight="100px" style="width: 100%;"/>
+            <div class="code-editor-wrapper" v-if="directive.directive === ''">
+                <HolderOutlined style="padding: 5px"/>
+                <code-editor v-model:content="directive.params"
+                             defaultHeight="100px" style="width: 100%;"/>
+            </div>
 
             <a-input v-else
                      v-model:value="directive.params" @click="current_idx=index">
@@ -91,6 +94,16 @@ function save() {
     margin: 15px 0;
 }
 
+.code-editor-wrapper {
+    display: flex;
+    width: 100%;
+    align-items: center;
+}
+
+.anticon-holder {
+    cursor: grab;
+}
+
 .directive-editor-extra {
     background-color: #fafafa;
     padding: 10px 20px;

+ 1 - 1
frontend/version.json

@@ -1 +1 @@
-{"version":"1.7.0","build_id":63,"total_build":133}
+{"version":"1.7.0","build_id":0,"total_build":0}

+ 149 - 149
frontend/yarn.lock

@@ -361,20 +361,120 @@
   resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz#75b4c27948c81e88ccd3a8902047bcd797f38d32"
   integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==
 
-"@esbuild/android-arm@0.15.13":
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.13.tgz#ce11237a13ee76d5eae3908e47ba4ddd380af86a"
-  integrity sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw==
+"@esbuild/android-arm64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.16.13.tgz#1fc9bfbff0bac558008b2ad7242db1c8024d8cfd"
+  integrity sha512-r4xetsd1ez1NF9/9R2f9Q6AlxqiZLwUqo7ICOcvEVwopVkXUcspIjEbJk0EVTgT6Cp5+ymzGPT6YNV0ievx4yA==
+
+"@esbuild/android-arm@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.16.13.tgz#df3317286eed68c727daf39c2d585625f9c2f170"
+  integrity sha512-JmtqThupn9Yf+FzANE+GG73ASUkssnPwOsndUElhp23685QzRK+MO1UompOlBaXV9D5FTuYcPnw7p4mCq2YbZQ==
+
+"@esbuild/android-x64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.16.13.tgz#c34826c4bdc57c60cbfb8d5bbd2306a89225626a"
+  integrity sha512-hKt1bFht/Vtp0xJ0ZVzFMnPy1y1ycmM3KNnp3zsyZfQmw7nhs2WLO4vxdR5YG+6RsHKCb2zbZ3VwlC0Tij0qyA==
+
+"@esbuild/darwin-arm64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.13.tgz#0b80c8580c262ccfb1203053201cf19c6f7b4cdb"
+  integrity sha512-ogrVuNi2URocrr3Ps20f075EMm9V7IeenOi9FRj4qdbT6mQlwLuP4l90PW2iBrKERx0oRkcZprEUNsz/3xd7ww==
+
+"@esbuild/darwin-x64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.16.13.tgz#f1a6c9ea67d4eaaf4944e1cbceb800eabc6e7e74"
+  integrity sha512-Agajik9SBGiKD7FPXE+ExW6x3MgA/dUdpZnXa9y1tyfE4lKQx+eQiknSdrBnWPeqa9wL0AOvkhghmYhpVkyqkA==
+
+"@esbuild/freebsd-arm64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.13.tgz#d1a45ac5c4a1be566c4eefbadbe5a967288ad338"
+  integrity sha512-KxMO3/XihBcHM+xQUM6nQZO1SgQuOsd1DCnKF1a4SIf/i5VD45vrqN3k8ePgFrEbMi7m5JeGmvNqwJXinF0a4Q==
+
+"@esbuild/freebsd-x64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.13.tgz#ec64a31cabb08343bb4520a221324b40509dffc8"
+  integrity sha512-Ez15oqV1vwvZ30cVLeBW14BsWq/fdWNQGMOxxqaSJVQVLqHhvgfQ7gxGDiN9tpJdeQhqJO+Q0r02/Tce5+USNg==
+
+"@esbuild/linux-arm64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.16.13.tgz#e8db3c3751b32ecf801751424eae43f6863a2ee7"
+  integrity sha512-qi5n7KwcGViyJeZeQnu8fB6dC3Mlm5PGaqSv2HhQDDx/MPvVfQGNMcv7zcBL4qk3FkuWhGVwXkjQ76x7R0PWlA==
+
+"@esbuild/linux-arm@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.16.13.tgz#ac0c8e9f3db8d418f588ae250e9c66ffdcf3cd82"
+  integrity sha512-18dLd2L3mda+iFj6sswyBMSh2UwniamD9M4DwPv8VM+9apRFlQ5IGKxBdumnTuOI4NvwwAernmUseWhYQ9k+rg==
+
+"@esbuild/linux-ia32@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.16.13.tgz#41ee9bd3b7161ab681fab6cb3990a3f5c08a9940"
+  integrity sha512-2489Xad9sr+6GD7nB913fUqpCsSwVwgskkQTq4Or2mZntSPYPebyJm8l1YruHo7oqYMTGV6RiwGE4gRo3H+EPQ==
 
 "@esbuild/linux-loong64@0.14.53":
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.53.tgz#251b4cd6760fadb4d68a05815e6dc5e432d69cd6"
   integrity sha512-W2dAL6Bnyn4xa/QRSU3ilIK4EzD5wgYXKXJiS1HDF5vU3675qc2bvFyLwbUcdmssDveyndy7FbitrCoiV/eMLg==
 
-"@esbuild/linux-loong64@0.15.13":
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz#64e8825bf0ce769dac94ee39d92ebe6272020dfc"
-  integrity sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag==
+"@esbuild/linux-loong64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.16.13.tgz#e4a832708e0b47078b91413edcfdb6af88c854a3"
+  integrity sha512-x8KplRu9Y43Px8I9YS+sPBwQ+fw44Mvp2BPVADopKDWz+h3fcj1BvRU58kxb89WObmwKX9sWdtYzepL4Fmx03A==
+
+"@esbuild/linux-mips64el@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.13.tgz#30d8571b71e0b8bf25fc5ef11422221ed23cdacc"
+  integrity sha512-qhhdWph9FLwD9rVVC/nUf7k2U4NZIA6/mGx0B7+O6PFV0GjmPA2E3zDQ4NUjq9P26E0DeAZy9akH9dYcUBRU7A==
+
+"@esbuild/linux-ppc64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.13.tgz#32a3855d4b79ba1d2b63dab592cb9f0d4a9ba485"
+  integrity sha512-cVWAPKsrRVxI1jCeJHnYSbE3BrEU+pZTZK2gfao9HRxuc+3m4+RLfs3EVEpGLmMKEcWfVCB9wZ3yNxnknutGKQ==
+
+"@esbuild/linux-riscv64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.13.tgz#6139202858da8202724d7079102614c269524f34"
+  integrity sha512-Agb7dbRyZWnmPn5Vvf0eyqaEUqSsaIUwwyInu2EoFTaIDRp093QU2M5alUyOooMLkRbD1WvqQNwx08Z/g+SAcQ==
+
+"@esbuild/linux-s390x@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.16.13.tgz#df3550a51e4155cde31486e01d8121f078e959ae"
+  integrity sha512-AqRBIrc/+kl08ahliNG+EyU+j41wIzQfwBTKpi80cCDiYvYFPuXjvzZsD9muiu58Isj0RVni9VgC4xK/AnSW4g==
+
+"@esbuild/linux-x64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.16.13.tgz#deb7951829ea5930e0d88440aeb5df0756ebb2d0"
+  integrity sha512-S4wn2BimuhPcoArRtVrdHUKIymCCZcYAXQE47kUiX4yrUrEX2/ifn5eKNbZ5c1jJKUlh1gC2ESIN+iw3wQax3g==
+
+"@esbuild/netbsd-x64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.13.tgz#8cba08074263862138cc5c63ad7f9640fe3faa69"
+  integrity sha512-2c8JWgfUMlQHTdaR5X3xNMwqOyad8kgeCupuVkdm3QkUOzGREjlTETQsK6oHifocYzDCo9FeKcUwsK356SdR+g==
+
+"@esbuild/openbsd-x64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.13.tgz#4ae19ac63c665424d248ba5c577618dd7bbcebd5"
+  integrity sha512-Bwh+PmKD/LK+xBjqIpnYnKYj0fIyQJ0YpRxsn0F+WfzvQ2OA+GKDlf8AHosiCns26Q4Dje388jQVwfOBZ1GaFw==
+
+"@esbuild/sunos-x64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.16.13.tgz#592caacab6b2c7669cd869b51f66dc354da03fc2"
+  integrity sha512-8wwk6f9XGnhrF94/DBdFM4Xm1JeCyGTCj67r516VS9yvBVQf3Rar54L+XPVDs/oZOokwH+XsktrgkuTMAmjntg==
+
+"@esbuild/win32-arm64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.16.13.tgz#965ebbe889e4221962250c55facaa1e48130c162"
+  integrity sha512-Jmwbp/5ArLCiRAHC33ODfcrlIcbP/exXkOEUVkADNJC4e/so2jm+i8IQFvVX/lA2GWvK3GdgcN0VFfp9YITAbg==
+
+"@esbuild/win32-ia32@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.16.13.tgz#1b04965bcf340ba4879b452ac32df63216d4c87e"
+  integrity sha512-AX6WjntGjhJHzrPSVvjMD7grxt41koHfAOx6lxLorrpDwwIKKPaGDASPZgvFIZHTbwhOtILW6vAXxYPDsKpDJA==
+
+"@esbuild/win32-x64@0.16.13":
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.16.13.tgz#0b0989cf0e7887cb0f3124e705cee68a694b96dd"
+  integrity sha512-A+U4gM6OOkPS03UgVU08GTpAAAxPsP/8Z4FmneGo4TaVSD99bK9gVJXlqUEPMO/htFXEAht2O6pX4ErtLY5tVg==
 
 "@jridgewell/gen-mapping@^0.1.0":
   version "0.1.1"
@@ -1442,201 +1542,101 @@ esbuild-android-64@0.14.53:
   resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.53.tgz#259bc3ef1399a3cad8f4f67c40ee20779c4de675"
   integrity sha512-fIL93sOTnEU+NrTAVMIKiAw0YH22HWCAgg4N4Z6zov2t0kY9RAJ50zY9ZMCQ+RT6bnOfDt8gCTnt/RaSNA2yRA==
 
-esbuild-android-64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz#5f25864055dbd62e250f360b38b4c382224063af"
-  integrity sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==
-
 esbuild-android-arm64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.53.tgz#2158253d4e8f9fdd2a081bbb4f73b8806178841e"
   integrity sha512-PC7KaF1v0h/nWpvlU1UMN7dzB54cBH8qSsm7S9mkwFA1BXpaEOufCg8hdoEI1jep0KeO/rjZVWrsH8+q28T77A==
 
-esbuild-android-arm64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz#d8820f999314efbe8e0f050653a99ff2da632b0f"
-  integrity sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==
-
 esbuild-darwin-64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.53.tgz#b4681831fd8f8d06feb5048acbe90d742074cc2a"
   integrity sha512-gE7P5wlnkX4d4PKvLBUgmhZXvL7lzGRLri17/+CmmCzfncIgq8lOBvxGMiQ4xazplhxq+72TEohyFMZLFxuWvg==
 
-esbuild-darwin-64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz#99ae7fdaa43947b06cd9d1a1c3c2c9f245d81fd0"
-  integrity sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==
-
 esbuild-darwin-arm64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.53.tgz#d267d957852d121b261b3f76ead86e5b5463acc9"
   integrity sha512-otJwDU3hnI15Q98PX4MJbknSZ/WSR1I45il7gcxcECXzfN4Mrpft5hBDHXNRnCh+5858uPXBXA1Vaz2jVWLaIA==
 
-esbuild-darwin-arm64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz#bafa1814354ad1a47adcad73de416130ef7f55e3"
-  integrity sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==
-
 esbuild-freebsd-64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.53.tgz#aca2af6d72b537fe66a38eb8f374fb66d4c98ca0"
   integrity sha512-WkdJa8iyrGHyKiPF4lk0MiOF87Q2SkE+i+8D4Cazq3/iqmGPJ6u49je300MFi5I2eUsQCkaOWhpCVQMTKGww2w==
 
-esbuild-freebsd-64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz#84ef85535c5cc38b627d1c5115623b088d1de161"
-  integrity sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==
-
 esbuild-freebsd-arm64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.53.tgz#76282e19312d914c34343c8a7da6cc5f051580b9"
   integrity sha512-9T7WwCuV30NAx0SyQpw8edbKvbKELnnm1FHg7gbSYaatH+c8WJW10g/OdM7JYnv7qkimw2ZTtSA+NokOLd2ydQ==
 
-esbuild-freebsd-arm64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz#033f21de434ec8e0c478054b119af8056763c2d8"
-  integrity sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==
-
 esbuild-linux-32@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.53.tgz#1045d34cf7c5faaf2af3b29cc1573b06580c37e5"
   integrity sha512-VGanLBg5en2LfGDgLEUxQko2lqsOS7MTEWUi8x91YmsHNyzJVT/WApbFFx3MQGhkf+XdimVhpyo5/G0PBY91zg==
 
-esbuild-linux-32@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz#54290ea8035cba0faf1791ce9ae6693005512535"
-  integrity sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==
-
 esbuild-linux-64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.53.tgz#ab3f2ee2ebb5a6930c72d9539cb34b428808cbe4"
   integrity sha512-pP/FA55j/fzAV7N9DF31meAyjOH6Bjuo3aSKPh26+RW85ZEtbJv9nhoxmGTd9FOqjx59Tc1ZbrJabuiXlMwuZQ==
 
-esbuild-linux-64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz#4264249281ea388ead948614b57fb1ddf7779a2c"
-  integrity sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==
-
 esbuild-linux-arm64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.53.tgz#1f5530412f6690949e78297122350488d3266cfe"
   integrity sha512-GDmWITT+PMsjCA6/lByYk7NyFssW4Q6in32iPkpjZ/ytSyH+xeEx8q7HG3AhWH6heemEYEWpTll/eui3jwlSnw==
 
-esbuild-linux-arm64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz#9323c333924f97a02bdd2ae8912b36298acb312d"
-  integrity sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==
-
 esbuild-linux-arm@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.53.tgz#a44ec9b5b42007ab6c0d65a224ccc6bbd97c54cf"
   integrity sha512-/u81NGAVZMopbmzd21Nu/wvnKQK3pT4CrvQ8BTje1STXcQAGnfyKgQlj3m0j2BzYbvQxSy+TMck4TNV2onvoPA==
 
-esbuild-linux-arm@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz#b407f47b3ae721fe4e00e19e9f19289bef87a111"
-  integrity sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==
-
 esbuild-linux-mips64le@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.53.tgz#a4d0b6b17cfdeea4e41b0b085a5f73d99311be9f"
   integrity sha512-d6/XHIQW714gSSp6tOOX2UscedVobELvQlPMkInhx1NPz4ThZI9uNLQ4qQJHGBGKGfu+rtJsxM4NVHLhnNRdWQ==
 
-esbuild-linux-mips64le@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz#bdf905aae5c0bcaa8f83567fe4c4c1bdc1f14447"
-  integrity sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==
-
 esbuild-linux-ppc64le@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.53.tgz#8c331822c85465434e086e3e6065863770c38139"
   integrity sha512-ndnJmniKPCB52m+r6BtHHLAOXw+xBCWIxNnedbIpuREOcbSU/AlyM/2dA3BmUQhsHdb4w3amD5U2s91TJ3MzzA==
 
-esbuild-linux-ppc64le@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz#2911eae1c90ff58a3bd3259cb557235df25aa3b4"
-  integrity sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==
-
 esbuild-linux-riscv64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.53.tgz#36fd75543401304bea8a2d63bf8ea18aaa508e00"
   integrity sha512-yG2sVH+QSix6ct4lIzJj329iJF3MhloLE6/vKMQAAd26UVPVkhMFqFopY+9kCgYsdeWvXdPgmyOuKa48Y7+/EQ==
 
-esbuild-linux-riscv64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz#1837c660be12b1d20d2a29c7189ea703f93e9265"
-  integrity sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==
-
 esbuild-linux-s390x@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.53.tgz#1622677ab6824123f48f75d3afc031cd41936129"
   integrity sha512-OCJlgdkB+XPYndHmw6uZT7jcYgzmx9K+28PVdOa/eLjdoYkeAFvH5hTwX4AXGLZLH09tpl4bVsEtvuyUldaNCg==
 
-esbuild-linux-s390x@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz#d52880ece229d1bd10b2d936b792914ffb07c7fc"
-  integrity sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==
-
 esbuild-netbsd-64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.53.tgz#e86d0efd0116658be335492ed12e66b26b4baf52"
   integrity sha512-gp2SB+Efc7MhMdWV2+pmIs/Ja/Mi5rjw+wlDmmbIn68VGXBleNgiEZG+eV2SRS0kJEUyHNedDtwRIMzaohWedQ==
 
-esbuild-netbsd-64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz#de14da46f1d20352b43e15d97a80a8788275e6ed"
-  integrity sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==
-
 esbuild-openbsd-64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.53.tgz#9bcbbe6f86304872c6e91f64c8eb73fc29c3588b"
   integrity sha512-eKQ30ZWe+WTZmteDYg8S+YjHV5s4iTxeSGhJKJajFfQx9TLZJvsJX0/paqwP51GicOUruFpSUAs2NCc0a4ivQQ==
 
-esbuild-openbsd-64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz#45e8a5fd74d92ad8f732c43582369c7990f5a0ac"
-  integrity sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==
-
 esbuild-sunos-64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.53.tgz#f7a872f7460bfb7b131f7188a95fbce3d1c577e8"
   integrity sha512-OWLpS7a2FrIRukQqcgQqR1XKn0jSJoOdT+RlhAxUoEQM/IpytS3FXzCJM6xjUYtpO5GMY0EdZJp+ur2pYdm39g==
 
-esbuild-sunos-64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz#f646ac3da7aac521ee0fdbc192750c87da697806"
-  integrity sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==
-
 esbuild-windows-32@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.53.tgz#c5e3ca50e2d1439cc2c9fe4defa63bcd474ce709"
   integrity sha512-m14XyWQP5rwGW0tbEfp95U6A0wY0DYPInWBB7D69FAXUpBpBObRoGTKRv36lf2RWOdE4YO3TNvj37zhXjVL5xg==
 
-esbuild-windows-32@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz#fb4fe77c7591418880b3c9b5900adc4c094f2401"
-  integrity sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==
-
 esbuild-windows-64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.53.tgz#ec2ab4a60c5215f092ffe1eab6d01319e88238af"
   integrity sha512-s9skQFF0I7zqnQ2K8S1xdLSfZFsPLuOGmSx57h2btSEswv0N0YodYvqLcJMrNMXh6EynOmWD7rz+0rWWbFpIHQ==
 
-esbuild-windows-64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz#1fca8c654392c0c31bdaaed168becfea80e20660"
-  integrity sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==
-
 esbuild-windows-arm64@0.14.53:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.53.tgz#f71d403806bdf9f4a1f9d097db9aec949bd675c8"
   integrity sha512-E+5Gvb+ZWts+00T9II6wp2L3KG2r3iGxByqd/a1RmLmYWVsSVUjkvIxZuJ3hYTIbhLkH5PRwpldGTKYqVz0nzQ==
 
-esbuild-windows-arm64@0.15.13:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz#4ffd01b6b2888603f1584a2fe96b1f6a6f2b3dd8"
-  integrity sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==
-
 esbuild@^0.14.47:
   version "0.14.53"
   resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.53.tgz#20b1007f686e8584f2a01a1bec5a37aac9498ce4"
@@ -1664,33 +1664,33 @@ esbuild@^0.14.47:
     esbuild-windows-64 "0.14.53"
     esbuild-windows-arm64 "0.14.53"
 
-esbuild@^0.15.9:
-  version "0.15.13"
-  resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.13.tgz#7293480038feb2bafa91d3f6a20edab3ba6c108a"
-  integrity sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==
+esbuild@^0.16.3:
+  version "0.16.13"
+  resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.16.13.tgz#83cd347c28221268bbfa0425db532d7d05f85b48"
+  integrity sha512-oYwFdSEIoKM1oYzyem1osgKJAvg5447XF+05ava21fOtilyb2HeQQh26/74K4WeAk5dZmj/Mx10zUqUnI14jhA==
   optionalDependencies:
-    "@esbuild/android-arm" "0.15.13"
-    "@esbuild/linux-loong64" "0.15.13"
-    esbuild-android-64 "0.15.13"
-    esbuild-android-arm64 "0.15.13"
-    esbuild-darwin-64 "0.15.13"
-    esbuild-darwin-arm64 "0.15.13"
-    esbuild-freebsd-64 "0.15.13"
-    esbuild-freebsd-arm64 "0.15.13"
-    esbuild-linux-32 "0.15.13"
-    esbuild-linux-64 "0.15.13"
-    esbuild-linux-arm "0.15.13"
-    esbuild-linux-arm64 "0.15.13"
-    esbuild-linux-mips64le "0.15.13"
-    esbuild-linux-ppc64le "0.15.13"
-    esbuild-linux-riscv64 "0.15.13"
-    esbuild-linux-s390x "0.15.13"
-    esbuild-netbsd-64 "0.15.13"
-    esbuild-openbsd-64 "0.15.13"
-    esbuild-sunos-64 "0.15.13"
-    esbuild-windows-32 "0.15.13"
-    esbuild-windows-64 "0.15.13"
-    esbuild-windows-arm64 "0.15.13"
+    "@esbuild/android-arm" "0.16.13"
+    "@esbuild/android-arm64" "0.16.13"
+    "@esbuild/android-x64" "0.16.13"
+    "@esbuild/darwin-arm64" "0.16.13"
+    "@esbuild/darwin-x64" "0.16.13"
+    "@esbuild/freebsd-arm64" "0.16.13"
+    "@esbuild/freebsd-x64" "0.16.13"
+    "@esbuild/linux-arm" "0.16.13"
+    "@esbuild/linux-arm64" "0.16.13"
+    "@esbuild/linux-ia32" "0.16.13"
+    "@esbuild/linux-loong64" "0.16.13"
+    "@esbuild/linux-mips64el" "0.16.13"
+    "@esbuild/linux-ppc64" "0.16.13"
+    "@esbuild/linux-riscv64" "0.16.13"
+    "@esbuild/linux-s390x" "0.16.13"
+    "@esbuild/linux-x64" "0.16.13"
+    "@esbuild/netbsd-x64" "0.16.13"
+    "@esbuild/openbsd-x64" "0.16.13"
+    "@esbuild/sunos-x64" "0.16.13"
+    "@esbuild/win32-arm64" "0.16.13"
+    "@esbuild/win32-ia32" "0.16.13"
+    "@esbuild/win32-x64" "0.16.13"
 
 escalade@^3.1.1:
   version "3.1.1"
@@ -2553,10 +2553,10 @@ postcss@^8.1.10, postcss@^8.2.9, postcss@^8.4.14:
     picocolors "^1.0.0"
     source-map-js "^1.0.2"
 
-postcss@^8.4.18:
-  version "8.4.19"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc"
-  integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==
+postcss@^8.4.20:
+  version "8.4.20"
+  resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.20.tgz#64c52f509644cecad8567e949f4081d98349dc56"
+  integrity sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==
   dependencies:
     nanoid "^3.3.4"
     picocolors "^1.0.0"
@@ -2642,10 +2642,10 @@ rollup@^2.75.6:
   optionalDependencies:
     fsevents "~2.3.2"
 
-rollup@^2.79.1:
-  version "2.79.1"
-  resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7"
-  integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
+rollup@^3.7.0:
+  version "3.9.1"
+  resolved "https://registry.npmmirror.com/rollup/-/rollup-3.9.1.tgz#27501d3d026418765fe379d5620d25954ff2a011"
+  integrity sha512-GswCYHXftN8ZKGVgQhTFUJB/NBXxrRGgO2NCy6E8s1rwEJ4Q9/VttNqcYfEvx4dTo4j58YqdC3OVztPzlKSX8w==
   optionalDependencies:
     fsevents "~2.3.2"
 
@@ -2972,15 +2972,15 @@ vite@^3.0.4:
   optionalDependencies:
     fsevents "~2.3.2"
 
-vite@^3.2.3:
-  version "3.2.3"
-  resolved "https://registry.yarnpkg.com/vite/-/vite-3.2.3.tgz#7a68d9ef73eff7ee6dc0718ad3507adfc86944a7"
-  integrity sha512-h8jl1TZ76eGs3o2dIBSsvXDLb1m/Ec1iej8ZMdz+PsaFUsftZeWe2CZOI3qogEsMNaywc17gu0q6cQDzh/weCQ==
+vite@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.npmmirror.com/vite/-/vite-4.0.3.tgz#de27ad3f263a03ae9419cdc8bc07721eadcba8b9"
+  integrity sha512-HvuNv1RdE7deIfQb8mPk51UKjqptO/4RXZ5yXSAvurd5xOckwS/gg8h9Tky3uSbnjYTgUm0hVCet1cyhKd73ZA==
   dependencies:
-    esbuild "^0.15.9"
-    postcss "^8.4.18"
+    esbuild "^0.16.3"
+    postcss "^8.4.20"
     resolve "^1.22.1"
-    rollup "^2.79.1"
+    rollup "^3.7.0"
   optionalDependencies:
     fsevents "~2.3.2"
 

+ 4 - 2
go.mod

@@ -2,10 +2,11 @@ module github.com/0xJacky/Nginx-UI
 
 go 1.19
 
+replace github.com/tufanbarisyildirim/gonginx v0.0.0-20220829083426-44da4d61ef9a => github.com/0xJacky/gonginx v0.0.0-20230104051937-4c3a63627efb
+
 require (
 	github.com/creack/pty v1.1.18
 	github.com/dustin/go-humanize v1.0.0
-	github.com/emirpasic/gods v1.18.1
 	github.com/gin-contrib/static v0.0.1
 	github.com/gin-gonic/gin v1.7.4
 	github.com/go-acme/lego/v4 v4.4.0
@@ -16,9 +17,11 @@ require (
 	github.com/golang-jwt/jwt v3.2.2+incompatible
 	github.com/google/uuid v1.1.1
 	github.com/gorilla/websocket v1.4.2
+	github.com/hpcloud/tail v1.0.0
 	github.com/pkg/errors v0.9.1
 	github.com/shirou/gopsutil/v3 v3.21.7
 	github.com/spf13/cast v1.3.1
+	github.com/tufanbarisyildirim/gonginx v0.0.0-20220829083426-44da4d61ef9a
 	github.com/unknwon/com v1.0.1
 	golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
 	gopkg.in/ini.v1 v1.62.0
@@ -32,7 +35,6 @@ require (
 	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/go-ole/go-ole v1.2.5 // indirect
 	github.com/golang/protobuf v1.3.4 // indirect
-	github.com/hpcloud/tail v1.0.0 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.2 // indirect
 	github.com/json-iterator/go v1.1.9 // indirect

+ 15 - 3
go.sum

@@ -23,6 +23,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
 cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
 contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/0xJacky/gonginx v0.0.0-20230104051937-4c3a63627efb h1:UzbGgIvP2UXpqlPG0ylT8/y0TIl5tBvAIeI3OAChFHI=
+github.com/0xJacky/gonginx v0.0.0-20230104051937-4c3a63627efb/go.mod h1:+uQMU+LMBHOQermcm/ICplG+r35Ypb6Up9iYKlvKuTE=
 github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
 github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg=
 github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
@@ -97,14 +99,13 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
 github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
 github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
-github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/exoscale/egoscale v0.46.0/go.mod h1:mpEXBpROAa/2i5GC0r33rfxG+TxSEka11g1PIXt9+zc=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -172,8 +173,10 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
+github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
 github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -446,6 +449,7 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2
 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
 go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
@@ -502,6 +506,7 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -529,6 +534,7 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d h1:1aflnvSoWWLI2k/dMUAl5lvU1YO4Mb4hz0gh+1rjcxU=
 golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@@ -543,6 +549,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -589,6 +596,7 @@ golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201110211018-35f3e6cf4a65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@@ -641,9 +649,11 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK
 golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@@ -725,6 +735,8 @@ gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9D
 gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
 gorm.io/gorm v1.21.14 h1:NAR9A/3SoyiPVHouW/rlpMUZvuQZ6Z6UYGz+2tosSQo=
 gorm.io/gorm v1.21.14/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
+gotest.tools/v3 v3.2.0 h1:I0DwBVMGAx26dttAj1BtJLAkVGncrkkUXfJLC4Flt/I=
+gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

+ 157 - 146
server/api/config.go

@@ -1,173 +1,184 @@
 package api
 
 import (
-    "github.com/0xJacky/Nginx-UI/server/pkg/config_list"
-    "github.com/0xJacky/Nginx-UI/server/pkg/nginx"
-    "github.com/gin-gonic/gin"
-    "log"
-    "net/http"
-    "os"
-    "path/filepath"
-    "strings"
+	"github.com/0xJacky/Nginx-UI/server/pkg/config_list"
+	"github.com/0xJacky/Nginx-UI/server/pkg/nginx"
+	"github.com/gin-gonic/gin"
+	"log"
+	"net/http"
+	"os"
+	"path/filepath"
+	"strings"
 )
 
 func GetConfigs(c *gin.Context) {
-    orderBy := c.Query("order_by")
-    sort := c.DefaultQuery("sort", "desc")
-    dir := c.DefaultQuery("dir", "/")
-
-    mySort := map[string]string{
-        "name":   "string",
-        "modify": "time",
-        "is_dir": "bool",
-    }
-
-    configFiles, err := os.ReadDir(nginx.GetNginxConfPath(dir))
-
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-
-    var configs []gin.H
-
-    for i := range configFiles {
-        file := configFiles[i]
-        fileInfo, _ := file.Info()
-
-        switch mode := fileInfo.Mode(); {
-        case mode.IsRegular(): // regular file, not a hidden file
-            if "." == file.Name()[0:1] {
-                continue
-            }
-        case mode&os.ModeSymlink != 0: // is a symbol
-            var targetPath string
-            targetPath, err = os.Readlink(nginx.GetNginxConfPath(file.Name()))
-            if err != nil {
-                log.Println("GetConfigs Read Symlink Error", targetPath, err)
-                continue
-            }
-        }
-
-        configs = append(configs, gin.H{
-            "name":   file.Name(),
-            "size":   fileInfo.Size(),
-            "modify": fileInfo.ModTime(),
-            "is_dir": file.IsDir(),
-        })
-    }
-
-    configs = config_list.Sort(orderBy, sort, mySort[orderBy], configs)
-
-    c.JSON(http.StatusOK, gin.H{
-        "data": configs,
-    })
+	orderBy := c.Query("order_by")
+	sort := c.DefaultQuery("sort", "desc")
+	dir := c.DefaultQuery("dir", "/")
+
+	mySort := map[string]string{
+		"name":   "string",
+		"modify": "time",
+		"is_dir": "bool",
+	}
+
+	configFiles, err := os.ReadDir(nginx.GetNginxConfPath(dir))
+
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+
+	var configs []gin.H
+
+	for i := range configFiles {
+		file := configFiles[i]
+		fileInfo, _ := file.Info()
+
+		switch mode := fileInfo.Mode(); {
+		case mode.IsRegular(): // regular file, not a hidden file
+			if "." == file.Name()[0:1] {
+				continue
+			}
+		case mode&os.ModeSymlink != 0: // is a symbol
+			var targetPath string
+			targetPath, err = os.Readlink(nginx.GetNginxConfPath(file.Name()))
+			if err != nil {
+				log.Println("GetConfigs Read Symlink Error", targetPath, err)
+				continue
+			}
+
+			var targetInfo os.FileInfo
+			targetInfo, err = os.Stat(targetPath)
+			if err != nil {
+				log.Println("GetConfigs Stat Error", targetPath, err)
+				continue
+			}
+			// but target file is not a dir
+			if targetInfo.IsDir() {
+				continue
+			}
+		}
+
+		configs = append(configs, gin.H{
+			"name":   file.Name(),
+			"size":   fileInfo.Size(),
+			"modify": fileInfo.ModTime(),
+			"is_dir": file.IsDir(),
+		})
+	}
+
+	configs = config_list.Sort(orderBy, sort, mySort[orderBy], configs)
+
+	c.JSON(http.StatusOK, gin.H{
+		"data": configs,
+	})
 }
 
 func GetConfig(c *gin.Context) {
-    name := c.Param("name")
-    path := filepath.Join(nginx.GetNginxConfPath("/"), name)
+	name := c.Param("name")
+	path := filepath.Join(nginx.GetNginxConfPath("/"), name)
 
-    content, err := os.ReadFile(path)
+	content, err := os.ReadFile(path)
 
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
 
-    c.JSON(http.StatusOK, gin.H{
-        "config": string(content),
-    })
+	c.JSON(http.StatusOK, gin.H{
+		"config": string(content),
+	})
 
 }
 
 type AddConfigJson struct {
-    Name    string `json:"name" binding:"required"`
-    Content string `json:"content" binding:"required"`
+	Name    string `json:"name" binding:"required"`
+	Content string `json:"content" binding:"required"`
 }
 
 func AddConfig(c *gin.Context) {
-    var request AddConfigJson
-    err := c.BindJSON(&request)
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-
-    name := request.Name
-    content := request.Content
-
-    path := filepath.Join(nginx.GetNginxConfPath("/"), name)
-
-    if _, err = os.Stat(path); err == nil {
-        c.JSON(http.StatusNotAcceptable, gin.H{
-            "message": "config exist",
-        })
-        return
-    }
-
-    if content != "" {
-        err = os.WriteFile(path, []byte(content), 0644)
-        if err != nil {
-            ErrHandler(c, err)
-            return
-        }
-    }
-
-    output := nginx.ReloadNginx()
-
-    if output != "" && strings.Contains(output, "error") {
-        c.JSON(http.StatusInternalServerError, gin.H{
-            "message": output,
-        })
-        return
-    }
-
-    c.JSON(http.StatusOK, gin.H{
-        "name":    name,
-        "content": content,
-    })
+	var request AddConfigJson
+	err := c.BindJSON(&request)
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+
+	name := request.Name
+	content := request.Content
+
+	path := filepath.Join(nginx.GetNginxConfPath("/"), name)
+
+	if _, err = os.Stat(path); err == nil {
+		c.JSON(http.StatusNotAcceptable, gin.H{
+			"message": "config exist",
+		})
+		return
+	}
+
+	if content != "" {
+		err = os.WriteFile(path, []byte(content), 0644)
+		if err != nil {
+			ErrHandler(c, err)
+			return
+		}
+	}
+
+	output := nginx.ReloadNginx()
+
+	if output != "" && strings.Contains(output, "error") {
+		c.JSON(http.StatusInternalServerError, gin.H{
+			"message": output,
+		})
+		return
+	}
+
+	c.JSON(http.StatusOK, gin.H{
+		"name":    name,
+		"content": content,
+	})
 
 }
 
 type EditConfigJson struct {
-    Content string `json:"content" binding:"required"`
+	Content string `json:"content" binding:"required"`
 }
 
 func EditConfig(c *gin.Context) {
-    name := c.Param("name")
-    var request EditConfigJson
-    err := c.BindJSON(&request)
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-    path := filepath.Join(nginx.GetNginxConfPath("/"), name)
-    content := request.Content
-
-    origContent, err := os.ReadFile(path)
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-
-    if content != "" && content != string(origContent) {
-        // model.CreateBackup(path)
-        err = os.WriteFile(path, []byte(content), 0644)
-        if err != nil {
-            ErrHandler(c, err)
-            return
-        }
-    }
-
-    output := nginx.ReloadNginx()
-
-    if output != "" && strings.Contains(output, "error") {
-        c.JSON(http.StatusInternalServerError, gin.H{
-            "message": output,
-        })
-        return
-    }
-
-    GetConfig(c)
+	name := c.Param("name")
+	var request EditConfigJson
+	err := c.BindJSON(&request)
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+	path := filepath.Join(nginx.GetNginxConfPath("/"), name)
+	content := request.Content
+
+	origContent, err := os.ReadFile(path)
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+
+	if content != "" && content != string(origContent) {
+		// model.CreateBackup(path)
+		err = os.WriteFile(path, []byte(content), 0644)
+		if err != nil {
+			ErrHandler(c, err)
+			return
+		}
+	}
+
+	output := nginx.ReloadNginx()
+
+	if output != "" && strings.Contains(output, "error") {
+		c.JSON(http.StatusInternalServerError, gin.H{
+			"message": output,
+		})
+		return
+	}
+
+	GetConfig(c)
 }

+ 329 - 329
server/api/domain.go

@@ -1,381 +1,381 @@
 package api
 
 import (
-    "github.com/0xJacky/Nginx-UI/server/model"
-    "github.com/0xJacky/Nginx-UI/server/pkg/cert"
-    "github.com/0xJacky/Nginx-UI/server/pkg/config_list"
-    "github.com/0xJacky/Nginx-UI/server/pkg/nginx"
-    "github.com/gin-gonic/gin"
-    "log"
-    "net/http"
-    "os"
-    "path/filepath"
-    "strings"
-    "time"
+	"github.com/0xJacky/Nginx-UI/server/model"
+	"github.com/0xJacky/Nginx-UI/server/pkg/cert"
+	"github.com/0xJacky/Nginx-UI/server/pkg/config_list"
+	"github.com/0xJacky/Nginx-UI/server/pkg/nginx"
+	"github.com/gin-gonic/gin"
+	"log"
+	"net/http"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
 )
 
 func GetDomains(c *gin.Context) {
-    name := c.Query("name")
-    orderBy := c.Query("order_by")
-    sort := c.DefaultQuery("sort", "desc")
-
-    mySort := map[string]string{
-        "enabled": "bool",
-        "name":    "string",
-        "modify":  "time",
-    }
-
-    configFiles, err := os.ReadDir(nginx.GetNginxConfPath("sites-available"))
-
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-
-    enabledConfig, err := os.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
-
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-
-    enabledConfigMap := make(map[string]bool)
-    for i := range enabledConfig {
-        enabledConfigMap[enabledConfig[i].Name()] = true
-    }
-
-    var configs []gin.H
-
-    for i := range configFiles {
-        file := configFiles[i]
-        fileInfo, _ := file.Info()
-        if !file.IsDir() {
-            if name != "" && !strings.Contains(file.Name(), name) {
-                continue
-            }
-            configs = append(configs, gin.H{
-                "name":    file.Name(),
-                "size":    fileInfo.Size(),
-                "modify":  fileInfo.ModTime(),
-                "enabled": enabledConfigMap[file.Name()],
-            })
-        }
-    }
-
-    configs = config_list.Sort(orderBy, sort, mySort[orderBy], configs)
-
-    c.JSON(http.StatusOK, gin.H{
-        "data": configs,
-    })
+	name := c.Query("name")
+	orderBy := c.Query("order_by")
+	sort := c.DefaultQuery("sort", "desc")
+
+	mySort := map[string]string{
+		"enabled": "bool",
+		"name":    "string",
+		"modify":  "time",
+	}
+
+	configFiles, err := os.ReadDir(nginx.GetNginxConfPath("sites-available"))
+
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+
+	enabledConfig, err := os.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
+
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+
+	enabledConfigMap := make(map[string]bool)
+	for i := range enabledConfig {
+		enabledConfigMap[enabledConfig[i].Name()] = true
+	}
+
+	var configs []gin.H
+
+	for i := range configFiles {
+		file := configFiles[i]
+		fileInfo, _ := file.Info()
+		if !file.IsDir() {
+			if name != "" && !strings.Contains(file.Name(), name) {
+				continue
+			}
+			configs = append(configs, gin.H{
+				"name":    file.Name(),
+				"size":    fileInfo.Size(),
+				"modify":  fileInfo.ModTime(),
+				"enabled": enabledConfigMap[file.Name()],
+			})
+		}
+	}
+
+	configs = config_list.Sort(orderBy, sort, mySort[orderBy], configs)
+
+	c.JSON(http.StatusOK, gin.H{
+		"data": configs,
+	})
 }
 
 type CertificateInfo struct {
-    SubjectName string    `json:"subject_name"`
-    IssuerName  string    `json:"issuer_name"`
-    NotAfter    time.Time `json:"not_after"`
-    NotBefore   time.Time `json:"not_before"`
+	SubjectName string    `json:"subject_name"`
+	IssuerName  string    `json:"issuer_name"`
+	NotAfter    time.Time `json:"not_after"`
+	NotBefore   time.Time `json:"not_before"`
 }
 
 func GetDomain(c *gin.Context) {
-    rewriteName, ok := c.Get("rewriteConfigFileName")
+	rewriteName, ok := c.Get("rewriteConfigFileName")
 
-    name := c.Param("name")
+	name := c.Param("name")
 
-    // for modify filename
-    if ok {
-        name = rewriteName.(string)
-    }
+	// for modify filename
+	if ok {
+		name = rewriteName.(string)
+	}
 
-    path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
+	path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
 
-    enabled := true
-    if _, err := os.Stat(filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) {
-        enabled = false
-    }
+	enabled := true
+	if _, err := os.Stat(filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) {
+		enabled = false
+	}
 
-    config, err := nginx.ParseNgxConfig(path)
+	config, err := nginx.ParseNgxConfig(path)
 
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
 
-    certInfoMap := make(map[int]CertificateInfo)
-    var serverName string
-    for serverIdx, server := range config.Servers {
-        for _, directive := range server.Directives {
+	certInfoMap := make(map[int]CertificateInfo)
+	var serverName string
+	for serverIdx, server := range config.Servers {
+		for _, directive := range server.Directives {
 
-            if directive.Directive == "server_name" {
-                serverName = strings.ReplaceAll(directive.Params, " ", "_")
-                continue
-            }
+			if directive.Directive == "server_name" {
+				serverName = strings.ReplaceAll(directive.Params, " ", "_")
+				continue
+			}
 
-            if directive.Directive == "ssl_certificate" {
+			if directive.Directive == "ssl_certificate" {
 
-                pubKey, err := cert.GetCertInfo(directive.Params)
+				pubKey, err := cert.GetCertInfo(directive.Params)
 
-                if err != nil {
-                    log.Println("Failed to get certificate information", err)
-                    break
-                }
+				if err != nil {
+					log.Println("Failed to get certificate information", err)
+					break
+				}
 
-                certInfoMap[serverIdx] = CertificateInfo{
-                    SubjectName: pubKey.Subject.CommonName,
-                    IssuerName:  pubKey.Issuer.CommonName,
-                    NotAfter:    pubKey.NotAfter,
-                    NotBefore:   pubKey.NotBefore,
-                }
+				certInfoMap[serverIdx] = CertificateInfo{
+					SubjectName: pubKey.Subject.CommonName,
+					IssuerName:  pubKey.Issuer.CommonName,
+					NotAfter:    pubKey.NotAfter,
+					NotBefore:   pubKey.NotBefore,
+				}
 
-                break
-            }
-        }
-    }
+				break
+			}
+		}
+	}
 
-    certModel, _ := model.FirstCert(serverName)
+	certModel, _ := model.FirstCert(serverName)
 
-    c.JSON(http.StatusOK, gin.H{
-        "enabled":   enabled,
-        "name":      name,
-        "config":    config.BuildConfig(),
-        "tokenized": config,
-        "auto_cert": certModel.AutoCert == model.AutoCertEnabled,
-        "cert_info": certInfoMap,
-    })
+	c.JSON(http.StatusOK, gin.H{
+		"enabled":   enabled,
+		"name":      name,
+		"config":    config.FmtCode(),
+		"tokenized": config,
+		"auto_cert": certModel.AutoCert == model.AutoCertEnabled,
+		"cert_info": certInfoMap,
+	})
 
 }
 
 func EditDomain(c *gin.Context) {
-    name := c.Param("name")
-
-    if name == "" {
-        c.JSON(http.StatusNotAcceptable, gin.H{
-            "message": "param name is empty",
-        })
-        return
-    }
-
-    var json struct {
-        Name    string `json:"name" binding:"required"`
-        Content string `json:"content"`
-    }
-
-    if !BindAndValid(c, &json) {
-        return
-    }
-
-    path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
-
-    err := os.WriteFile(path, []byte(json.Content), 0644)
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-    enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
-    // rename the config file if needed
-    if name != json.Name {
-        newPath := filepath.Join(nginx.GetNginxConfPath("sites-available"), json.Name)
-        // recreate soft link
-        log.Println(enabledConfigFilePath)
-        if _, err = os.Stat(enabledConfigFilePath); err == nil {
-            log.Println(enabledConfigFilePath)
-            _ = os.Remove(enabledConfigFilePath)
-            enabledConfigFilePath = filepath.Join(nginx.GetNginxConfPath("sites-enabled"), json.Name)
-            err = os.Symlink(newPath, enabledConfigFilePath)
-
-            if err != nil {
-                ErrHandler(c, err)
-                return
-            }
-        }
-        err = os.Rename(path, newPath)
-        if err != nil {
-            ErrHandler(c, err)
-            return
-        }
-        name = json.Name
-        c.Set("rewriteConfigFileName", name)
-
-    }
-
-    enabledConfigFilePath = filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
-    if _, err = os.Stat(enabledConfigFilePath); err == nil {
-        // Test nginx configuration
-        err = nginx.TestNginxConf()
-        if err != nil {
-            c.JSON(http.StatusInternalServerError, gin.H{
-                "message": err.Error(),
-            })
-            return
-        }
-
-        output := nginx.ReloadNginx()
-
-        if output != "" && strings.Contains(output, "error") {
-            c.JSON(http.StatusInternalServerError, gin.H{
-                "message": output,
-            })
-            return
-        }
-    }
-
-    GetDomain(c)
+	name := c.Param("name")
+
+	if name == "" {
+		c.JSON(http.StatusNotAcceptable, gin.H{
+			"message": "param name is empty",
+		})
+		return
+	}
+
+	var json struct {
+		Name    string `json:"name" binding:"required"`
+		Content string `json:"content"`
+	}
+
+	if !BindAndValid(c, &json) {
+		return
+	}
+
+	path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
+
+	err := os.WriteFile(path, []byte(json.Content), 0644)
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+	enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
+	// rename the config file if needed
+	if name != json.Name {
+		newPath := filepath.Join(nginx.GetNginxConfPath("sites-available"), json.Name)
+		// recreate soft link
+		log.Println(enabledConfigFilePath)
+		if _, err = os.Stat(enabledConfigFilePath); err == nil {
+			log.Println(enabledConfigFilePath)
+			_ = os.Remove(enabledConfigFilePath)
+			enabledConfigFilePath = filepath.Join(nginx.GetNginxConfPath("sites-enabled"), json.Name)
+			err = os.Symlink(newPath, enabledConfigFilePath)
+
+			if err != nil {
+				ErrHandler(c, err)
+				return
+			}
+		}
+		err = os.Rename(path, newPath)
+		if err != nil {
+			ErrHandler(c, err)
+			return
+		}
+		name = json.Name
+		c.Set("rewriteConfigFileName", name)
+
+	}
+
+	enabledConfigFilePath = filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
+	if _, err = os.Stat(enabledConfigFilePath); err == nil {
+		// Test nginx configuration
+		err = nginx.TestNginxConf()
+		if err != nil {
+			c.JSON(http.StatusInternalServerError, gin.H{
+				"message": err.Error(),
+			})
+			return
+		}
+
+		output := nginx.ReloadNginx()
+
+		if output != "" && strings.Contains(output, "error") {
+			c.JSON(http.StatusInternalServerError, gin.H{
+				"message": output,
+			})
+			return
+		}
+	}
+
+	GetDomain(c)
 }
 
 func EnableDomain(c *gin.Context) {
-    configFilePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), c.Param("name"))
-    enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
-
-    _, err := os.Stat(configFilePath)
-
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-
-    if _, err = os.Stat(enabledConfigFilePath); os.IsNotExist(err) {
-        err = os.Symlink(configFilePath, enabledConfigFilePath)
-
-        if err != nil {
-            ErrHandler(c, err)
-            return
-        }
-    }
-
-    // Test nginx config, if not pass then rollback.
-    err = nginx.TestNginxConf()
-    if err != nil {
-        _ = os.Remove(enabledConfigFilePath)
-        c.JSON(http.StatusInternalServerError, gin.H{
-            "message": err.Error(),
-        })
-        return
-    }
-
-    output := nginx.ReloadNginx()
-
-    if output != "" && strings.Contains(output, "error") {
-        c.JSON(http.StatusInternalServerError, gin.H{
-            "message": output,
-        })
-        return
-    }
-
-    c.JSON(http.StatusOK, gin.H{
-        "message": "ok",
-    })
+	configFilePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), c.Param("name"))
+	enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
+
+	_, err := os.Stat(configFilePath)
+
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+
+	if _, err = os.Stat(enabledConfigFilePath); os.IsNotExist(err) {
+		err = os.Symlink(configFilePath, enabledConfigFilePath)
+
+		if err != nil {
+			ErrHandler(c, err)
+			return
+		}
+	}
+
+	// Test nginx config, if not pass then rollback.
+	err = nginx.TestNginxConf()
+	if err != nil {
+		_ = os.Remove(enabledConfigFilePath)
+		c.JSON(http.StatusInternalServerError, gin.H{
+			"message": err.Error(),
+		})
+		return
+	}
+
+	output := nginx.ReloadNginx()
+
+	if output != "" && strings.Contains(output, "error") {
+		c.JSON(http.StatusInternalServerError, gin.H{
+			"message": output,
+		})
+		return
+	}
+
+	c.JSON(http.StatusOK, gin.H{
+		"message": "ok",
+	})
 }
 
 func DisableDomain(c *gin.Context) {
-    enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
-
-    _, err := os.Stat(enabledConfigFilePath)
-
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-
-    err = os.Remove(enabledConfigFilePath)
-
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-
-    // delete auto cert record
-    certModel := model.Cert{Domain: c.Param("name")}
-    err = certModel.Remove()
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-
-    output := nginx.ReloadNginx()
-
-    if output != "" {
-        c.JSON(http.StatusInternalServerError, gin.H{
-            "message": output,
-        })
-        return
-    }
-
-    c.JSON(http.StatusOK, gin.H{
-        "message": "ok",
-    })
+	enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
+
+	_, err := os.Stat(enabledConfigFilePath)
+
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+
+	err = os.Remove(enabledConfigFilePath)
+
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+
+	// delete auto cert record
+	certModel := model.Cert{Domain: c.Param("name")}
+	err = certModel.Remove()
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+
+	output := nginx.ReloadNginx()
+
+	if output != "" {
+		c.JSON(http.StatusInternalServerError, gin.H{
+			"message": output,
+		})
+		return
+	}
+
+	c.JSON(http.StatusOK, gin.H{
+		"message": "ok",
+	})
 }
 
 func DeleteDomain(c *gin.Context) {
-    var err error
-    name := c.Param("name")
-    availablePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
-    enabledPath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
-
-    if _, err = os.Stat(availablePath); os.IsNotExist(err) {
-        c.JSON(http.StatusNotFound, gin.H{
-            "message": "site not found",
-        })
-        return
-    }
-
-    if _, err = os.Stat(enabledPath); err == nil {
-        c.JSON(http.StatusNotAcceptable, gin.H{
-            "message": "site is enabled",
-        })
-        return
-    }
-
-    certModel := model.Cert{Domain: name}
-    _ = certModel.Remove()
-
-    err = os.Remove(availablePath)
-
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-
-    c.JSON(http.StatusOK, gin.H{
-        "message": "ok",
-    })
+	var err error
+	name := c.Param("name")
+	availablePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
+	enabledPath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
+
+	if _, err = os.Stat(availablePath); os.IsNotExist(err) {
+		c.JSON(http.StatusNotFound, gin.H{
+			"message": "site not found",
+		})
+		return
+	}
+
+	if _, err = os.Stat(enabledPath); err == nil {
+		c.JSON(http.StatusNotAcceptable, gin.H{
+			"message": "site is enabled",
+		})
+		return
+	}
+
+	certModel := model.Cert{Domain: name}
+	_ = certModel.Remove()
+
+	err = os.Remove(availablePath)
+
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+
+	c.JSON(http.StatusOK, gin.H{
+		"message": "ok",
+	})
 
 }
 
 func AddDomainToAutoCert(c *gin.Context) {
-    domain := c.Param("domain")
-    domain = strings.ReplaceAll(domain, " ", "_")
-    certModel, err := model.FirstOrCreateCert(domain)
+	domain := c.Param("domain")
+	domain = strings.ReplaceAll(domain, " ", "_")
+	certModel, err := model.FirstOrCreateCert(domain)
 
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
 
-    err = certModel.Updates(&model.Cert{
-        AutoCert: model.AutoCertEnabled,
-    })
+	err = certModel.Updates(&model.Cert{
+		AutoCert: model.AutoCertEnabled,
+	})
 
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
 
-    c.JSON(http.StatusOK, certModel)
+	c.JSON(http.StatusOK, certModel)
 }
 
 func RemoveDomainFromAutoCert(c *gin.Context) {
-    domain := c.Param("domain")
-    domain = strings.ReplaceAll(domain, " ", "_")
-    certModel := model.Cert{
-        Domain: domain,
-    }
-
-    err := certModel.Updates(&model.Cert{
-        AutoCert: model.AutoCertDisabled,
-    })
-
-    if err != nil {
-        ErrHandler(c, err)
-        return
-    }
-    c.JSON(http.StatusOK, nil)
+	domain := c.Param("domain")
+	domain = strings.ReplaceAll(domain, " ", "_")
+	certModel := model.Cert{
+		Domain: domain,
+	}
+
+	err := certModel.Updates(&model.Cert{
+		AutoCert: model.AutoCertDisabled,
+	})
+
+	if err != nil {
+		ErrHandler(c, err)
+		return
+	}
+	c.JSON(http.StatusOK, nil)
 }

+ 3 - 12
server/api/ngx.go

@@ -1,15 +1,13 @@
 package api
 
 import (
-	"bufio"
-	nginx2 "github.com/0xJacky/Nginx-UI/server/pkg/nginx"
+	"github.com/0xJacky/Nginx-UI/server/pkg/nginx"
 	"github.com/gin-gonic/gin"
 	"net/http"
-	"strings"
 )
 
 func BuildNginxConfig(c *gin.Context) {
-	var ngxConf nginx2.NgxConfig
+	var ngxConf nginx.NgxConfig
 	if !BindAndValid(c, &ngxConf) {
 		return
 	}
@@ -28,14 +26,7 @@ func TokenizeNginxConfig(c *gin.Context) {
 		return
 	}
 
-	scanner := bufio.NewScanner(strings.NewReader(json.Content))
-
-	ngxConfig, err := nginx2.ParseNgxConfigByScanner("", scanner)
-
-	if err != nil {
-		ErrHandler(c, err)
-		return
-	}
+	ngxConfig := nginx.ParseNgxConfigByContent(json.Content)
 
 	c.JSON(http.StatusOK, ngxConfig)
 

+ 70 - 68
server/pkg/nginx/build_config.go

@@ -1,88 +1,90 @@
 package nginx
 
 import (
-    "bufio"
-    "fmt"
-    "strings"
+	"bufio"
+	"fmt"
+	"github.com/tufanbarisyildirim/gonginx"
+	"github.com/tufanbarisyildirim/gonginx/parser"
+	"strings"
 )
 
 func buildComments(orig string, indent int) (content string) {
-    scanner := bufio.NewScanner(strings.NewReader(orig))
-    for scanner.Scan() {
-        content += strings.Repeat("\t", indent) + "# " + scanner.Text() + "\n"
-    }
-    content = strings.TrimLeft(content, "\n")
-    return
+	scanner := bufio.NewScanner(strings.NewReader(orig))
+	for scanner.Scan() {
+		content += strings.Repeat("\t", indent) + "# " + scanner.Text() + "\n"
+	}
+	content = strings.TrimLeft(content, "\n")
+	return
 }
 
 func (c *NgxConfig) BuildConfig() (content string) {
 
-    // Custom
-    if c.Custom != "" {
-        content += fmtCode(c.Custom)
-        content += "\n\n"
-    }
+	// Custom
+	if c.Custom != "" {
+		content += c.Custom
+		content += "\n\n"
+	}
 
-    // Upstreams
-    for _, u := range c.Upstreams {
+	// Upstreams
+	for _, u := range c.Upstreams {
 
-        upstream := ""
-        var comments string
-        for _, directive := range u.Directives {
-            if directive.Comments != "" {
-                comments = buildComments(directive.Comments, 1)
-            }
-            upstream += fmt.Sprintf("%s\t%s;\n", comments, directive.Orig())
-        }
-        comments = buildComments(u.Comments, 1)
-        content += fmt.Sprintf("upstream %s {\n%s%s}\n\n", u.Name, comments, upstream)
-    }
+		upstream := ""
+		var comments string
+		for _, directive := range u.Directives {
+			if directive.Comments != "" {
+				comments = buildComments(directive.Comments, 1)
+			}
+			upstream += fmt.Sprintf("%s\t%s;\n", comments, directive.Orig())
+		}
+		comments = buildComments(u.Comments, 1)
+		content += fmt.Sprintf("upstream %s {\n%s%s}\n\n", u.Name, comments, upstream)
+	}
 
-    // Servers
-    for _, s := range c.Servers {
-        server := ""
+	// Servers
+	for _, s := range c.Servers {
+		server := ""
 
-        // directives
-        for _, directive := range s.Directives {
-            var comments string
-            if directive.Comments != "" {
-                comments = buildComments(directive.Comments, 1)
-            }
-            if directive.Directive == If {
-                server += fmt.Sprintf("%s%s\n", comments, fmtCodeWithIndent(directive.Params, 1))
-            } else if directive.Params != "" {
-                server += fmt.Sprintf("%s\t%s;\n", comments, directive.Orig())
-            }
-        }
+		// directives
+		for _, directive := range s.Directives {
+			var comments string
+			if directive.Comments != "" {
+				comments = buildComments(directive.Comments, 1)
+			}
+			if directive.Params != "" {
+				server += fmt.Sprintf("%s\t%s;\n", comments, directive.Orig())
+			}
+		}
 
-        if len(s.Directives) > 0 {
-            server += "\n"
-        }
+		if len(s.Directives) > 0 {
+			server += "\n"
+		}
 
-        // locations
-        locations := ""
-        for _, location := range s.Locations {
-            locationContent := ""
-            scanner := bufio.NewScanner(strings.NewReader(location.Content))
-            for scanner.Scan() {
-                locationContent += "\t\t" + scanner.Text() + "\n"
-            }
-            var comments string
-            if location.Comments != "" {
-                comments = buildComments(location.Comments, 1)
-            }
-            locations += fmt.Sprintf("%s\tlocation %s {\n%s\t}\n\n", comments, location.Path, locationContent)
-        }
+		// locations
+		locations := ""
+		for _, location := range s.Locations {
+			locationContent := ""
+			scanner := bufio.NewScanner(strings.NewReader(location.Content))
+			for scanner.Scan() {
+				locationContent += "\t\t" + scanner.Text() + "\n"
+			}
+			var comments string
+			if location.Comments != "" {
+				comments = buildComments(location.Comments, 1)
+			}
+			locations += fmt.Sprintf("%s\tlocation %s {\n%s\t}\n\n", comments, location.Path, locationContent)
+		}
 
-        server += locations
+		server += locations
 
-        var comments string
-        if s.Comments != "" {
-            comments = buildComments(s.Comments, 0) + "\n"
-        }
+		var comments string
+		if s.Comments != "" {
+			comments = buildComments(s.Comments, 0) + "\n"
+		}
 
-        content += fmt.Sprintf("%sserver {\n%s}\n\n", comments, server)
-    }
-
-    return
+		content += fmt.Sprintf("%sserver {\n%s}\n\n", comments, server)
+	}
+	p := parser.NewStringParser(content)
+	config := p.Parse()
+	content = gonginx.DumpConfig(config, gonginx.IndentedStyle)
+	return
 }

+ 0 - 0
server/test/nextcloud_ngx.conf → server/pkg/nginx/conf/nextcloud_ngx.conf


+ 36 - 0
server/pkg/nginx/conf/test.conf

@@ -0,0 +1,36 @@
+map $http_upgrade $connection_upgrade {
+	default upgrade;
+	'' close;
+}
+
+server {
+	listen 80;
+	listen [::]:80;
+	server_name blog.jackyu.cn test.jackyu.cn;
+
+	location /.well-known/acme-challenge {
+		proxy_set_header Host $host;
+		proxy_set_header X-Real_IP $remote_addr;
+		proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
+		proxy_pass http://127.0.0.1:9180;
+	}
+
+}
+
+server {
+	listen 443 ssl http2;
+	listen [::]:443 ssl http2;
+	server_name blog.jackyu.cn test.jackyu.cn;
+	ssl_certificate /etc/nginx/ssl/blog.jackyu.cn_test.jackyu.cn/fullchain.cer;
+	ssl_certificate_key /etc/nginx/ssl/blog.jackyu.cn_test.jackyu.cn/private.key;
+	include enable-php-8.conf;
+
+	location /.well-known/acme-challenge {
+		proxy_set_header Host $host;
+		proxy_set_header X-Real_IP $remote_addr;
+		proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
+		proxy_pass http://127.0.0.1:9180;
+	}
+
+}
+

+ 4 - 43
server/pkg/nginx/format_code.go

@@ -1,49 +1,10 @@
 package nginx
 
 import (
-    "bufio"
-    "github.com/emirpasic/gods/stacks/linkedliststack"
-    "strings"
+	"github.com/tufanbarisyildirim/gonginx"
 )
 
-func fmtCode(content string) (fmtContent string) {
-    fmtContent = fmtCodeWithIndent(content, 0)
-    return
-}
-
-func fmtCodeWithIndent(content string, indent int) (fmtContent string) {
-    /*
-       Format content
-       1. TrimSpace for each line
-       2. use stack to count how many \t should add
-    */
-    stack := linkedliststack.New()
-
-    scanner := bufio.NewScanner(strings.NewReader(content))
-
-    for scanner.Scan() {
-        text := scanner.Text()
-        text = strings.TrimSpace(text)
-
-        before := stack.Size()
-
-        for _, char := range text {
-            matchParentheses(stack, char)
-        }
-
-        after := stack.Size()
-
-        fmtContent += strings.Repeat("\t", indent)
-
-        if before == after {
-            fmtContent += strings.Repeat("\t", stack.Size()) + text + "\n"
-        } else {
-            fmtContent += text + "\n"
-        }
-
-    }
-
-    fmtContent = strings.Trim(fmtContent, "\n")
-
-    return
+func (c *NgxConfig) FmtCode() (fmtContent string) {
+	fmtContent = gonginx.DumpConfig(c.c, gonginx.IndentedStyle)
+	return
 }

+ 49 - 0
server/pkg/nginx/ngx_conf_parse_test.go

@@ -0,0 +1,49 @@
+package nginx
+
+import (
+	"fmt"
+	"github.com/tufanbarisyildirim/gonginx"
+	"github.com/tufanbarisyildirim/gonginx/parser"
+	"strings"
+	"testing"
+)
+
+func TestNgxConfParse(t *testing.T) {
+	p, err := parser.NewParser("conf/nextcloud_ngx.conf")
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	n := p.Parse()
+
+	fn(n.Block, 0)
+
+	c, err := ParseNgxConfig("conf/nextcloud_ngx.conf")
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	fmt.Println(c)
+	c, err = ParseNgxConfig("conf/test.conf")
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	fmt.Println(c)
+}
+
+func fn(block gonginx.IBlock, deep int) {
+	if block == nil {
+		return
+	}
+	for _, v := range block.GetDirectives() {
+		if len(v.GetComment()) > 0 {
+			for _, c := range v.GetComment() {
+				fmt.Println(strings.Repeat("\t", deep), c)
+			}
+		}
+
+		fmt.Println(fmt.Sprintf("%s%s %s", strings.Repeat("\t", deep), v.GetName(), strings.Join(v.GetParameters(), " ")))
+		fn(v.GetBlock(), deep+1)
+	}
+}

+ 118 - 110
server/pkg/nginx/parse.go

@@ -1,150 +1,158 @@
 package nginx
 
 import (
-	"bufio"
-	"github.com/emirpasic/gods/stacks/linkedliststack"
 	"github.com/pkg/errors"
-	"os"
+	"github.com/tufanbarisyildirim/gonginx"
+	"github.com/tufanbarisyildirim/gonginx/parser"
 	"strings"
-	"unicode"
 )
 
 const (
-	Server       = "server"
-	Location     = "location"
-	Upstream     = "upstream"
-	CommentStart = "#"
-	Empty        = ""
-	If           = "if"
+	Server   = "server"
+	Location = "location"
+	Upstream = "upstream"
 )
 
-func matchParentheses(stack *linkedliststack.Stack, v int32) {
-	if v == '{' {
-		stack.Push(v)
-	} else if v == '}' {
-		// stack is not empty and the top is == '{'
-		if top, ok := stack.Peek(); ok && top == '{' {
-			stack.Pop()
-		} else {
-			// fail
-			stack.Push(v)
+func (s *NgxServer) parseServer(directive gonginx.IDirective) {
+	if directive.GetBlock() == nil {
+		return
+	}
+	for _, d := range directive.GetBlock().GetDirectives() {
+		switch d.GetName() {
+		case Location:
+			location := &NgxLocation{
+				Path:     strings.Join(d.GetParameters(), " "),
+				Comments: buildComment(d.GetComment()),
+			}
+			location.parseLocation(d, 0)
+			s.Locations = append(s.Locations, location)
+		default:
+			dir := &NgxDirective{
+				Directive: d.GetName(),
+				Comments:  buildComment(d.GetComment()),
+			}
+			dir.parseDirective(d, 0)
+			s.Directives = append(s.Directives, dir)
 		}
 	}
 }
 
-func parseDirective(scanner *bufio.Scanner) (d NgxDirective) {
-	text := strings.TrimSpace(scanner.Text())
-	// escape empty line or comment line
-	if len(text) < 1 {
-		return
-	}
-
-	if text[0] == '#' {
-		d.Directive = "#"
-		d.Params = strings.TrimLeft(text, "#")
+func (l *NgxLocation) parseLocation(directive gonginx.IDirective, deep int) {
+	if directive.GetBlock() == nil {
 		return
 	}
-
-	if len(text) > 1 {
-		sep := len(text) - 1
-		for k, v := range text {
-			if unicode.IsSpace(v) {
-				sep = k
-				break
+	for _, location := range directive.GetBlock().GetDirectives() {
+		if len(location.GetComment()) > 0 {
+			for _, c := range location.GetComment() {
+				l.Content += strings.Repeat("\t", deep) + c + "\n"
 			}
 		}
-
-		d.Directive = text[0:sep]
-		d.Params = text[sep:]
-	} else {
-		d.Directive = text
-		return
+		l.Content += strings.Repeat("\t", deep) + location.GetName() + " " + strings.Join(location.GetParameters(), " ") + ";\n"
+		l.parseLocation(location, deep+1)
 	}
+}
 
-	stack := linkedliststack.New()
-
-	if d.Directive == Server || d.Directive == Upstream || d.Directive == Location || d.Directive == If {
-		// { } in one line
-		// location = /.well-known/carddav { return 301 /remote.php/dav/; }
-		if strings.Contains(d.Params, "{") {
-			for _, v := range d.Params {
-				matchParentheses(stack, v)
-			}
-
-			if stack.Empty() {
-				return
+func (d *NgxDirective) parseDirective(directive gonginx.IDirective, deep int) {
+	if directive.GetBlock() != nil {
+		d.Params += directive.GetName() + " "
+		d.Directive = ""
+	}
+	d.Params += strings.Join(directive.GetParameters(), " ")
+	if directive.GetBlock() != nil {
+		d.Params += " {\n"
+		for _, location := range directive.GetBlock().GetDirectives() {
+			if len(location.GetComment()) > 0 {
+				for _, c := range location.GetComment() {
+					d.Params += strings.Repeat("\t", deep) + c + "\n"
+				}
 			}
-		}
-
-		// location ^~ /.well-known {
-		// location ^~ /.well-known
-		// {
-		// location ^~ /.well-known
-		//
-		//    {
-		// { } not in one line
-		for scanner.Scan() {
-			text = strings.TrimSpace(scanner.Text())
-			// escape empty line
-			if text == "" {
+			d.Params += strings.Repeat("\t", deep+1) + location.GetName() + " " +
+				strings.Join(location.GetParameters(), " ") + ";\n"
+			// d.parseDirective(location, deep+1)
+			if location.GetBlock() == nil {
 				continue
 			}
-			d.Params += "\n" + scanner.Text()
-			for _, v := range text {
-				matchParentheses(stack, v)
-				if stack.Empty() {
-					break
-				}
-			}
-			if stack.Empty() {
-				break
+			for _, v := range location.GetBlock().GetDirectives() {
+				d.parseDirective(v, deep+1)
 			}
 		}
+		d.Params += "}\n"
+		return
 	}
-	d.Params = strings.TrimSpace(d.Params)
-	return
 }
 
-func ParseNgxConfigByScanner(filename string, scanner *bufio.Scanner) (c *NgxConfig, err error) {
-	c = NewNgxConfig(filename)
-
-	for scanner.Scan() {
-		d := parseDirective(scanner)
-		paramsScanner := bufio.NewScanner(strings.NewReader(d.Params))
-		switch d.Directive {
-		case Server:
-			c.parseServer(paramsScanner)
-		case Upstream:
-			c.parseUpstream(paramsScanner)
-		case CommentStart:
-			c.commentQueue.Enqueue(d.Params)
-		case Empty:
-			continue
-		default:
-			c.Custom += d.Orig() + "\n"
+func (u *NgxUpstream) parseUpstream(directive gonginx.IDirective) {
+	if directive.GetBlock() == nil {
+		return
+	}
+	for _, us := range directive.GetBlock().GetDirectives() {
+		d := &NgxDirective{
+			Directive: us.GetName(),
+			Params:    strings.Join(us.GetParameters(), " "),
+			Comments:  buildComment(us.GetComment()),
 		}
+		u.Directives = append(u.Directives, d)
 	}
+}
 
-	if err = scanner.Err(); err != nil {
-		return nil, errors.Wrap(err, "error scanner in ParseNgxConfig")
+func (c *NgxConfig) parseCustom(directive gonginx.IDirective) {
+	if directive.GetBlock() == nil {
+		return
 	}
-
-	// Attach the rest of the comments to the last server
-	if len(c.Servers) > 0 {
-		c.Servers[len(c.Servers)-1].Comments += c.commentQueue.DequeueAllComments()
+	c.Custom += "{\n"
+	for _, v := range directive.GetBlock().GetDirectives() {
+		c.Custom += strings.Join(v.GetComment(), "\n") + "\n" +
+			v.GetName() + " " + strings.Join(v.GetParameters(), " ") + ";\n"
 	}
+	c.Custom += "}\n"
+}
 
-	return c, nil
+func buildComment(c []string) string {
+	return strings.ReplaceAll(strings.Join(c, "\n"), "#", "")
 }
 
-func ParseNgxConfig(filename string) (c *NgxConfig, err error) {
-	file, err := os.Open(filename)
-	if err != nil {
-		return nil, errors.Wrap(err, "error open file in ParseNgxConfig")
+func parse(block gonginx.IBlock, ngxConfig *NgxConfig) {
+	if block == nil {
+		return
 	}
-	defer file.Close()
+	for _, v := range block.GetDirectives() {
+		comments := buildComment(v.GetComment())
+		switch v.GetName() {
+		case Server:
+			server := NewNgxServer()
+			server.Comments = comments
+			server.parseServer(v)
+			ngxConfig.Servers = append(ngxConfig.Servers, server)
+		case Upstream:
+			upstream := &NgxUpstream{}
+			upstream.Comments = comments
+			upstream.parseUpstream(v)
+			ngxConfig.Upstreams = append(ngxConfig.Upstreams, upstream)
+		default:
+			ngxConfig.Custom += strings.Join(v.GetComment(), "\n") + "\n" +
+				v.GetName() + " " + strings.Join(v.GetParameters(), " ") + "\n"
+			ngxConfig.parseCustom(v)
+		}
+	}
+}
 
-	scanner := bufio.NewScanner(file)
+func ParseNgxConfigByContent(content string) (ngxConfig *NgxConfig) {
+	p := parser.NewStringParser(content)
+	c := p.Parse()
+	ngxConfig = NewNgxConfig("")
+	ngxConfig.c = c
+	parse(c.Block, ngxConfig)
+	return
+}
 
-	return ParseNgxConfigByScanner(filename, scanner)
+func ParseNgxConfig(filename string) (ngxConfig *NgxConfig, err error) {
+	p, err := parser.NewParser(filename)
+	if err != nil {
+		return nil, errors.Wrap(err, "error ParseNgxConfig")
+	}
+	c := p.Parse()
+	ngxConfig = NewNgxConfig(filename)
+	ngxConfig.c = c
+	parse(c.Block, ngxConfig)
+	return
 }

+ 0 - 125
server/pkg/nginx/tokenize.go

@@ -1,125 +0,0 @@
-package nginx
-
-import (
-	"bufio"
-	"regexp"
-	"strings"
-	"unicode"
-)
-
-func (c *NgxConfig) parseServer(scanner *bufio.Scanner) {
-	server := NewNgxServer()
-	for scanner.Scan() {
-		d := parseDirective(scanner)
-		switch d.Directive {
-		case Location:
-			server.parseLocation(d.Params)
-		case CommentStart:
-			server.commentQueue.Enqueue(d.Params)
-		default:
-			server.parseDirective(d)
-		}
-	}
-	// Attach the rest of the comments to the last location
-	if len(server.Locations) > 0 {
-		server.Locations[len(server.Locations)-1].Comments += server.commentQueue.DequeueAllComments()
-	}
-
-	// Attach comments which are over the current server
-	server.Comments = c.commentQueue.DequeueAllComments()
-
-	c.Servers = append(c.Servers, server)
-}
-
-func (c *NgxConfig) parseUpstream(scanner *bufio.Scanner) {
-	upstream := &NgxUpstream{}
-	for scanner.Scan() {
-		d := NgxDirective{}
-		text := strings.TrimSpace(scanner.Text())
-		// escape empty line or comment line
-		if len(text) < 1 || text[0] == '#' {
-			return
-		}
-
-		sep := len(text) - 1
-		for k, v := range text {
-			if unicode.IsSpace(v) {
-				sep = k
-				break
-			}
-		}
-
-		d.Directive = text[0:sep]
-		d.Params = strings.Trim(text[sep:], ";")
-
-		if d.Directive == Server {
-			upstream.Directives = append(upstream.Directives, &d)
-		} else if upstream.Name == "" {
-			upstream.Name = d.Directive
-		}
-	}
-	// attach comments which are over the current upstream
-	upstream.Comments = c.commentQueue.DequeueAllComments()
-
-	c.Upstreams = append(c.Upstreams, upstream)
-}
-
-func (s *NgxServer) parseDirective(d NgxDirective) {
-	orig := d.Orig()
-	// handle inline comments
-	str, comments, _ := strings.Cut(orig, "#")
-
-	if d.Directive == If {
-		d.Params = "if " + d.Params
-		d.Params = fmtCode(d.Params)
-		s.Directives = append(s.Directives, &d)
-		return
-	}
-
-	regExp := regexp.MustCompile("(\\S+?)\\s+?{?(.+)[;|}]")
-	matchSlice := regExp.FindAllStringSubmatch(str, -1)
-
-	for k, v := range matchSlice {
-		// [[gzip_min_length 256; gzip_min_length 256] [gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; gzip_proxied expired no-cache no-store private no_last_modified no_etag auth] [gzip on; gzip on] [gzip_vary on; gzip_vary on] [location /x/ {} location /x/ {] [gzip_comp_level 4; gzip_comp_level 4]]
-		if len(v) > 0 {
-			scanner := bufio.NewScanner(strings.NewReader(v[0]))
-			if scanner.Scan() {
-				d = parseDirective(scanner)
-				// inline location
-				if d.Directive == Location {
-					s.parseLocation(d.Orig())
-				} else {
-
-					if k == 0 {
-						d.Comments = s.commentQueue.DequeueAllComments()
-					} else if k == len(matchSlice)-1 {
-						d.Comments = comments
-					}
-
-					// trim right ';'
-					d.TrimParams()
-					// map[directive]=>[]Params
-					s.Directives = append(s.Directives, &d)
-				}
-
-			}
-		}
-	}
-}
-
-func (s *NgxServer) parseLocation(str string) {
-	path, content, _ := strings.Cut(str, "{")
-	path = strings.TrimSpace(path)
-
-	content = strings.TrimSpace(content)
-	content = strings.Trim(content, "}")
-
-	content = fmtCode(content)
-
-	location := &NgxLocation{
-		Path:    path,
-		Content: content,
-	}
-	location.Comments = s.commentQueue.DequeueAllComments()
-	s.Locations = append(s.Locations, location)
-}

+ 13 - 32
server/pkg/nginx/type.go

@@ -1,27 +1,22 @@
 package nginx
 
 import (
-	"github.com/emirpasic/gods/queues/linkedlistqueue"
+	"github.com/tufanbarisyildirim/gonginx"
 	"strings"
 )
 
-type CommentQueue struct {
-	*linkedlistqueue.Queue
-}
-
 type NgxConfig struct {
-	FileName     string         `json:"file_name"`
-	Upstreams    []*NgxUpstream `json:"upstreams"`
-	Servers      []*NgxServer   `json:"servers"`
-	Custom       string         `json:"custom"`
-	commentQueue *CommentQueue
+	FileName  string         `json:"file_name"`
+	Upstreams []*NgxUpstream `json:"upstreams"`
+	Servers   []*NgxServer   `json:"servers"`
+	Custom    string         `json:"custom"`
+	c         *gonginx.Config
 }
 
 type NgxServer struct {
-	Directives   []*NgxDirective `json:"directives"`
-	Locations    []*NgxLocation  `json:"locations"`
-	Comments     string          `json:"comments"`
-	commentQueue *CommentQueue
+	Directives []*NgxDirective `json:"directives"`
+	Locations  []*NgxLocation  `json:"locations"`
+	Comments   string          `json:"comments"`
 }
 
 type NgxUpstream struct {
@@ -42,18 +37,6 @@ type NgxLocation struct {
 	Comments string `json:"comments"`
 }
 
-func (c *CommentQueue) DequeueAllComments() (comments string) {
-	for !c.Empty() {
-		comment, ok := c.Dequeue()
-
-		if ok {
-			comments += strings.TrimSpace(comment.(string)) + "\n"
-		}
-	}
-
-	return
-}
-
 func (d *NgxDirective) Orig() string {
 	return d.Directive + " " + d.Params
 }
@@ -65,16 +48,14 @@ func (d *NgxDirective) TrimParams() {
 
 func NewNgxServer() *NgxServer {
 	return &NgxServer{
-		Locations:    make([]*NgxLocation, 0),
-		Directives:   make([]*NgxDirective, 0),
-		commentQueue: &CommentQueue{linkedlistqueue.New()},
+		Locations:  make([]*NgxLocation, 0),
+		Directives: make([]*NgxDirective, 0),
 	}
 }
 
 func NewNgxConfig(filename string) *NgxConfig {
 	return &NgxConfig{
-		FileName:     filename,
-		commentQueue: &CommentQueue{linkedlistqueue.New()},
-		Upstreams:    make([]*NgxUpstream, 0),
+		FileName:  filename,
+		Upstreams: make([]*NgxUpstream, 0),
 	}
 }

+ 0 - 42
server/test/ngx_conf_parse_test.go

@@ -1,42 +0,0 @@
-package test
-
-import (
-	"fmt"
-	"github.com/0xJacky/Nginx-UI/server/pkg/nginx"
-	"testing"
-)
-
-func TestNgxConfParse(t *testing.T) {
-	c, err := nginx.ParseNgxConfig("nextcloud_ngx.conf")
-
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	fmt.Println(c.FileName)
-	// directive in root
-	fmt.Println("Upstream")
-	for _, u := range c.Upstreams {
-		fmt.Println("upstream name", u.Name)
-		fmt.Printf("comments\n%v", u.Comments)
-		for _, d := range u.Directives {
-			fmt.Println("u.Directives.d", d)
-		}
-	}
-	fmt.Println("==========================")
-	fmt.Println("Servers")
-	for _, s := range c.Servers {
-		fmt.Printf("comments\n%v", s.Comments)
-		for _, d := range s.Directives {
-			fmt.Println(d)
-		}
-		// locations
-		for _, location := range s.Locations {
-			fmt.Printf("comments\n%v", location.Comments)
-			fmt.Println("path", location.Path)
-			fmt.Println("content", location.Content)
-			fmt.Println("==========================")
-		}
-	}
-
-}