🎉 Basic Web Sideload
This commit is contained in:
		
							
								
								
									
										59
									
								
								.idea/codeStyles/Project.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								.idea/codeStyles/Project.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					<component name="ProjectCodeStyleConfiguration">
 | 
				
			||||||
 | 
					  <code_scheme name="Project" version="173">
 | 
				
			||||||
 | 
					    <HTMLCodeStyleSettings>
 | 
				
			||||||
 | 
					      <option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
 | 
				
			||||||
 | 
					    </HTMLCodeStyleSettings>
 | 
				
			||||||
 | 
					    <JSCodeStyleSettings version="0">
 | 
				
			||||||
 | 
					      <option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
 | 
				
			||||||
 | 
					      <option name="FORCE_SEMICOLON_STYLE" value="true" />
 | 
				
			||||||
 | 
					      <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
 | 
				
			||||||
 | 
					      <option name="FORCE_QUOTE_STYlE" value="true" />
 | 
				
			||||||
 | 
					      <option name="ENFORCE_TRAILING_COMMA" value="Remove" />
 | 
				
			||||||
 | 
					      <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
 | 
				
			||||||
 | 
					      <option name="SPACES_WITHIN_IMPORTS" value="true" />
 | 
				
			||||||
 | 
					    </JSCodeStyleSettings>
 | 
				
			||||||
 | 
					    <TypeScriptCodeStyleSettings version="0">
 | 
				
			||||||
 | 
					      <option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
 | 
				
			||||||
 | 
					      <option name="FORCE_SEMICOLON_STYLE" value="true" />
 | 
				
			||||||
 | 
					      <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
 | 
				
			||||||
 | 
					      <option name="FORCE_QUOTE_STYlE" value="true" />
 | 
				
			||||||
 | 
					      <option name="ENFORCE_TRAILING_COMMA" value="Remove" />
 | 
				
			||||||
 | 
					      <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
 | 
				
			||||||
 | 
					      <option name="SPACES_WITHIN_IMPORTS" value="true" />
 | 
				
			||||||
 | 
					    </TypeScriptCodeStyleSettings>
 | 
				
			||||||
 | 
					    <VueCodeStyleSettings>
 | 
				
			||||||
 | 
					      <option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
 | 
				
			||||||
 | 
					      <option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
 | 
				
			||||||
 | 
					    </VueCodeStyleSettings>
 | 
				
			||||||
 | 
					    <codeStyleSettings language="HTML">
 | 
				
			||||||
 | 
					      <option name="SOFT_MARGINS" value="120" />
 | 
				
			||||||
 | 
					      <indentOptions>
 | 
				
			||||||
 | 
					        <option name="INDENT_SIZE" value="2" />
 | 
				
			||||||
 | 
					        <option name="CONTINUATION_INDENT_SIZE" value="2" />
 | 
				
			||||||
 | 
					        <option name="TAB_SIZE" value="2" />
 | 
				
			||||||
 | 
					      </indentOptions>
 | 
				
			||||||
 | 
					    </codeStyleSettings>
 | 
				
			||||||
 | 
					    <codeStyleSettings language="JavaScript">
 | 
				
			||||||
 | 
					      <option name="SOFT_MARGINS" value="120" />
 | 
				
			||||||
 | 
					      <indentOptions>
 | 
				
			||||||
 | 
					        <option name="INDENT_SIZE" value="2" />
 | 
				
			||||||
 | 
					        <option name="CONTINUATION_INDENT_SIZE" value="2" />
 | 
				
			||||||
 | 
					        <option name="TAB_SIZE" value="2" />
 | 
				
			||||||
 | 
					      </indentOptions>
 | 
				
			||||||
 | 
					    </codeStyleSettings>
 | 
				
			||||||
 | 
					    <codeStyleSettings language="TypeScript">
 | 
				
			||||||
 | 
					      <option name="SOFT_MARGINS" value="120" />
 | 
				
			||||||
 | 
					      <indentOptions>
 | 
				
			||||||
 | 
					        <option name="INDENT_SIZE" value="2" />
 | 
				
			||||||
 | 
					        <option name="CONTINUATION_INDENT_SIZE" value="2" />
 | 
				
			||||||
 | 
					        <option name="TAB_SIZE" value="2" />
 | 
				
			||||||
 | 
					      </indentOptions>
 | 
				
			||||||
 | 
					    </codeStyleSettings>
 | 
				
			||||||
 | 
					    <codeStyleSettings language="Vue">
 | 
				
			||||||
 | 
					      <option name="SOFT_MARGINS" value="120" />
 | 
				
			||||||
 | 
					      <indentOptions>
 | 
				
			||||||
 | 
					        <option name="CONTINUATION_INDENT_SIZE" value="2" />
 | 
				
			||||||
 | 
					      </indentOptions>
 | 
				
			||||||
 | 
					    </codeStyleSettings>
 | 
				
			||||||
 | 
					  </code_scheme>
 | 
				
			||||||
 | 
					</component>
 | 
				
			||||||
							
								
								
									
										5
									
								
								.idea/codeStyles/codeStyleConfig.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.idea/codeStyles/codeStyleConfig.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					<component name="ProjectCodeStyleConfiguration">
 | 
				
			||||||
 | 
					  <state>
 | 
				
			||||||
 | 
					    <option name="USE_PER_PROJECT_SETTINGS" value="true" />
 | 
				
			||||||
 | 
					  </state>
 | 
				
			||||||
 | 
					</component>
 | 
				
			||||||
@@ -15,8 +15,8 @@ import (
 | 
				
			|||||||
func doPublish(c *fiber.Ctx) error {
 | 
					func doPublish(c *fiber.Ctx) error {
 | 
				
			||||||
	var workdir string
 | 
						var workdir string
 | 
				
			||||||
	var site *sign.SiteConfig
 | 
						var site *sign.SiteConfig
 | 
				
			||||||
	var upstream *sign.UpstreamConfig
 | 
						var upstream *sign.UpstreamInstance
 | 
				
			||||||
	var process *sign.ProcessConfig
 | 
						var process *sign.ProcessInstance
 | 
				
			||||||
	for _, item := range sign.App.Sites {
 | 
						for _, item := range sign.App.Sites {
 | 
				
			||||||
		if item.ID == c.Params("site") {
 | 
							if item.ID == c.Params("site") {
 | 
				
			||||||
			site = item
 | 
								site = item
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,9 @@ func InitSideload() *fiber.App {
 | 
				
			|||||||
	cgi := app.Group("/cgi").Name("CGI")
 | 
						cgi := app.Group("/cgi").Name("CGI")
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		cgi.All("/connectivity", responseConnectivity)
 | 
							cgi.All("/connectivity", responseConnectivity)
 | 
				
			||||||
 | 
							cgi.Get("/statistics", getStatistics)
 | 
				
			||||||
 | 
							cgi.Get("/sites", getSites)
 | 
				
			||||||
 | 
							cgi.Get("/sites/cfg/:id", getSiteConfig)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	webhooks := app.Group("/webhooks").Name("WebHooks")
 | 
						webhooks := app.Group("/webhooks").Name("WebHooks")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,24 @@ import (
 | 
				
			|||||||
	"gopkg.in/yaml.v2"
 | 
						"gopkg.in/yaml.v2"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getSites(c *fiber.Ctx) error {
 | 
				
			||||||
 | 
						return c.JSON(sign.App.Sites)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getSiteConfig(c *fiber.Ctx) error {
 | 
				
			||||||
 | 
						fp := filepath.Join(viper.GetString("paths.configs"), c.Params("id"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						var data []byte
 | 
				
			||||||
 | 
						if data, err = os.ReadFile(fp + ".yml"); err != nil {
 | 
				
			||||||
 | 
							if data, err = os.ReadFile(fp + ".yaml"); err != nil {
 | 
				
			||||||
 | 
								return fiber.NewError(fiber.StatusNotFound, err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return c.Type("yaml").SendString(string(data))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func doSyncSite(c *fiber.Ctx) error {
 | 
					func doSyncSite(c *fiber.Ctx) error {
 | 
				
			||||||
	var req sign.SiteConfig
 | 
						var req sign.SiteConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										28
									
								
								pkg/sideload/statistics.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								pkg/sideload/statistics.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					package sideload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"code.smartsheep.studio/goatworks/roadsign/pkg/sign"
 | 
				
			||||||
 | 
						"github.com/gofiber/fiber/v2"
 | 
				
			||||||
 | 
						"github.com/samber/lo"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getStatistics(c *fiber.Ctx) error {
 | 
				
			||||||
 | 
						upstreams := lo.FlatMap(sign.App.Sites, func(item *sign.SiteConfig, idx int) []*sign.UpstreamInstance {
 | 
				
			||||||
 | 
							return item.Upstreams
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						processes := lo.FlatMap(sign.App.Sites, func(item *sign.SiteConfig, idx int) []*sign.ProcessInstance {
 | 
				
			||||||
 | 
							return item.Processes
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						unhealthy := lo.FlatMap(sign.App.Sites, func(item *sign.SiteConfig, idx int) []*sign.ProcessInstance {
 | 
				
			||||||
 | 
							return lo.Filter(item.Processes, func(item *sign.ProcessInstance, idx int) bool {
 | 
				
			||||||
 | 
								return item.Status != sign.ProcessStarted
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return c.JSON(fiber.Map{
 | 
				
			||||||
 | 
							"sites":     len(sign.App.Sites),
 | 
				
			||||||
 | 
							"upstreams": len(upstreams),
 | 
				
			||||||
 | 
							"processes": len(processes),
 | 
				
			||||||
 | 
							"status":    len(unhealthy) == 0,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								pkg/sideload/view/.eslintrc.cjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								pkg/sideload/view/.eslintrc.cjs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					/* eslint-env node */
 | 
				
			||||||
 | 
					require('@rushstack/eslint-patch/modern-module-resolution')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  root: true,
 | 
				
			||||||
 | 
					  'extends': [
 | 
				
			||||||
 | 
					    'plugin:vue/vue3-essential',
 | 
				
			||||||
 | 
					    'eslint:recommended',
 | 
				
			||||||
 | 
					    '@vue/eslint-config-typescript',
 | 
				
			||||||
 | 
					    '@vue/eslint-config-prettier/skip-formatting'
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  parserOptions: {
 | 
				
			||||||
 | 
					    ecmaVersion: 'latest'
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								pkg/sideload/view/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								pkg/sideload/view/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					# Logs
 | 
				
			||||||
 | 
					logs
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					npm-debug.log*
 | 
				
			||||||
 | 
					yarn-debug.log*
 | 
				
			||||||
 | 
					yarn-error.log*
 | 
				
			||||||
 | 
					pnpm-debug.log*
 | 
				
			||||||
 | 
					lerna-debug.log*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					node_modules
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					dist
 | 
				
			||||||
 | 
					dist-ssr
 | 
				
			||||||
 | 
					coverage
 | 
				
			||||||
 | 
					*.local
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/cypress/videos/
 | 
				
			||||||
 | 
					/cypress/screenshots/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Editor directories and files
 | 
				
			||||||
 | 
					.vscode/*
 | 
				
			||||||
 | 
					!.vscode/extensions.json
 | 
				
			||||||
 | 
					.idea
 | 
				
			||||||
 | 
					*.suo
 | 
				
			||||||
 | 
					*.ntvs*
 | 
				
			||||||
 | 
					*.njsproj
 | 
				
			||||||
 | 
					*.sln
 | 
				
			||||||
 | 
					*.sw?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*.tsbuildinfo
 | 
				
			||||||
							
								
								
									
										8
									
								
								pkg/sideload/view/.prettierrc.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								pkg/sideload/view/.prettierrc.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "$schema": "https://json.schemastore.org/prettierrc",
 | 
				
			||||||
 | 
					  "semi": false,
 | 
				
			||||||
 | 
					  "tabWidth": 2,
 | 
				
			||||||
 | 
					  "singleQuote": false,
 | 
				
			||||||
 | 
					  "printWidth": 120,
 | 
				
			||||||
 | 
					  "trailingComma": "none"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								pkg/sideload/view/.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								pkg/sideload/view/.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "recommendations": [
 | 
				
			||||||
 | 
					    "Vue.volar",
 | 
				
			||||||
 | 
					    "Vue.vscode-typescript-vue-plugin",
 | 
				
			||||||
 | 
					    "dbaeumer.vscode-eslint",
 | 
				
			||||||
 | 
					    "esbenp.prettier-vscode"
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										46
									
								
								pkg/sideload/view/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								pkg/sideload/view/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					# @roadsign/sideload-ui
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This template should help get you started developing with Vue 3 in Vite.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Recommended IDE Setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Type Support for `.vue` Imports in TS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Disable the built-in TypeScript Extension
 | 
				
			||||||
 | 
					    1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
 | 
				
			||||||
 | 
					    2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
 | 
				
			||||||
 | 
					2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Customize configuration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See [Vite Configuration Reference](https://vitejs.dev/config/).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Project Setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sh
 | 
				
			||||||
 | 
					yarn
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Compile and Hot-Reload for Development
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sh
 | 
				
			||||||
 | 
					yarn dev
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Type-Check, Compile and Minify for Production
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sh
 | 
				
			||||||
 | 
					yarn build
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Lint with [ESLint](https://eslint.org/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sh
 | 
				
			||||||
 | 
					yarn lint
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										6
									
								
								pkg/sideload/view/embed.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								pkg/sideload/view/embed.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					package view
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "embed"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//go:embed all:dist
 | 
				
			||||||
 | 
					var FS embed.FS
 | 
				
			||||||
							
								
								
									
										1
									
								
								pkg/sideload/view/env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								pkg/sideload/view/env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					/// <reference types="vite/client" />
 | 
				
			||||||
							
								
								
									
										13
									
								
								pkg/sideload/view/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								pkg/sideload/view/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html lang="en">
 | 
				
			||||||
 | 
					  <head>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
 | 
					    <link rel="icon" href="/favicon.ico">
 | 
				
			||||||
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
				
			||||||
 | 
					    <title>RoadSign</title>
 | 
				
			||||||
 | 
					  </head>
 | 
				
			||||||
 | 
					  <body>
 | 
				
			||||||
 | 
					    <div id="app"></div>
 | 
				
			||||||
 | 
					    <script type="module" src="/src/main.ts"></script>
 | 
				
			||||||
 | 
					  </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										44
									
								
								pkg/sideload/view/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								pkg/sideload/view/package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "@roadsign/sideload-ui",
 | 
				
			||||||
 | 
					  "version": "0.0.0",
 | 
				
			||||||
 | 
					  "private": true,
 | 
				
			||||||
 | 
					  "type": "module",
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "dev": "vite",
 | 
				
			||||||
 | 
					    "build": "run-p type-check \"build-only {@}\" --",
 | 
				
			||||||
 | 
					    "preview": "vite preview",
 | 
				
			||||||
 | 
					    "build-only": "vite build",
 | 
				
			||||||
 | 
					    "type-check": "vue-tsc --build --force",
 | 
				
			||||||
 | 
					    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
 | 
				
			||||||
 | 
					    "format": "prettier --write src/"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "@guolao/vue-monaco-editor": "^1.4.1",
 | 
				
			||||||
 | 
					    "highlight.js": "^11.9.0",
 | 
				
			||||||
 | 
					    "js-yaml": "^4.1.0",
 | 
				
			||||||
 | 
					    "pinia": "^2.1.7",
 | 
				
			||||||
 | 
					    "vue": "^3.3.11",
 | 
				
			||||||
 | 
					    "vue-router": "^4.2.5"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "@rushstack/eslint-patch": "^1.3.3",
 | 
				
			||||||
 | 
					    "@tsconfig/node18": "^18.2.2",
 | 
				
			||||||
 | 
					    "@types/js-yaml": "^4.0.9",
 | 
				
			||||||
 | 
					    "@types/node": "^18.19.3",
 | 
				
			||||||
 | 
					    "@vicons/carbon": "^0.12.0",
 | 
				
			||||||
 | 
					    "@vitejs/plugin-vue": "^4.5.2",
 | 
				
			||||||
 | 
					    "@vue/eslint-config-prettier": "^8.0.0",
 | 
				
			||||||
 | 
					    "@vue/eslint-config-typescript": "^12.0.0",
 | 
				
			||||||
 | 
					    "@vue/tsconfig": "^0.5.0",
 | 
				
			||||||
 | 
					    "eslint": "^8.49.0",
 | 
				
			||||||
 | 
					    "eslint-plugin-vue": "^9.17.0",
 | 
				
			||||||
 | 
					    "naive-ui": "^2.36.0",
 | 
				
			||||||
 | 
					    "npm-run-all2": "^6.1.1",
 | 
				
			||||||
 | 
					    "prettier": "^3.0.3",
 | 
				
			||||||
 | 
					    "typescript": "~5.3.0",
 | 
				
			||||||
 | 
					    "unocss": "^0.58.2",
 | 
				
			||||||
 | 
					    "vfonts": "^0.0.3",
 | 
				
			||||||
 | 
					    "vite": "^5.0.10",
 | 
				
			||||||
 | 
					    "vue-tsc": "^1.8.25"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								pkg/sideload/view/src/assets/main.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								pkg/sideload/view/src/assets/main.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					@import "vfonts/IBMPlexSans.css";
 | 
				
			||||||
 | 
					@import "vfonts/IBMPlexMono.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					a {
 | 
				
			||||||
 | 
					    color: #3f7ee8;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										133
									
								
								pkg/sideload/view/src/components/data/sites-table-action.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								pkg/sideload/view/src/components/data/sites-table-action.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="flex gap-[4px]">
 | 
				
			||||||
 | 
					    <n-button size="small" @click="publishing = true">
 | 
				
			||||||
 | 
					      <template #icon>
 | 
				
			||||||
 | 
					        <n-icon :component="CloudUpload" />
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					    </n-button>
 | 
				
			||||||
 | 
					    <n-button size="small" @click="editConfig()">
 | 
				
			||||||
 | 
					      <template #icon>
 | 
				
			||||||
 | 
					        <n-icon :component="Edit" />
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					    </n-button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <n-modal
 | 
				
			||||||
 | 
					      v-model:show="publishing"
 | 
				
			||||||
 | 
					      class="w-[720px]"
 | 
				
			||||||
 | 
					      preset="card"
 | 
				
			||||||
 | 
					      title="Publish Artifacts"
 | 
				
			||||||
 | 
					      segmented
 | 
				
			||||||
 | 
					      closable
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      We are sorry about this tool isn't completed yet. <br>
 | 
				
			||||||
 | 
					      For now, you can use our <b>Wonderful Command Line Tool —— RDS</b> <br>
 | 
				
			||||||
 | 
					      Learn more on our <a href="https://wiki.smartsheep.studio/roadsign/index.html" target="_blank">official wiki</a>.
 | 
				
			||||||
 | 
					      <br>
 | 
				
			||||||
 | 
					      <br>
 | 
				
			||||||
 | 
					      Install it by this command below
 | 
				
			||||||
 | 
					      <n-code code="go install code.smartsheep.studio/goatworks/roadsign/pkg/cmd/rds@latest" />
 | 
				
			||||||
 | 
					      <br>
 | 
				
			||||||
 | 
					      Then connect your rds client to this server
 | 
				
			||||||
 | 
					      <n-code :code="`rds connect <name> ${host} <credentials>`" />
 | 
				
			||||||
 | 
					      <br>
 | 
				
			||||||
 | 
					      After that you can publish your stuff (You need to compress them to zip archive before publish)
 | 
				
			||||||
 | 
					      <n-code :code="`rds deploy <name> ${props.id} <upstream id or process id>`" />
 | 
				
			||||||
 | 
					    </n-modal>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <n-modal
 | 
				
			||||||
 | 
					      v-model:show="editing"
 | 
				
			||||||
 | 
					      class="w-[720px]"
 | 
				
			||||||
 | 
					      content-style="padding: 0"
 | 
				
			||||||
 | 
					      preset="card"
 | 
				
			||||||
 | 
					      title="Edit Configuration"
 | 
				
			||||||
 | 
					      segmented
 | 
				
			||||||
 | 
					      closable
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <div class="relative h-[540px]">
 | 
				
			||||||
 | 
					        <vue-monaco-editor
 | 
				
			||||||
 | 
					          v-model:value="config"
 | 
				
			||||||
 | 
					          :options="{ automaticLayout: true, minimap: { enabled: false } }"
 | 
				
			||||||
 | 
					          language="yaml"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="fab">
 | 
				
			||||||
 | 
					          <n-tooltip placement="left">
 | 
				
			||||||
 | 
					            <template #trigger>
 | 
				
			||||||
 | 
					              <n-button
 | 
				
			||||||
 | 
					                circle
 | 
				
			||||||
 | 
					                type="primary"
 | 
				
			||||||
 | 
					                size="large"
 | 
				
			||||||
 | 
					                class="shadow-lg"
 | 
				
			||||||
 | 
					                :loading="submitting"
 | 
				
			||||||
 | 
					                @click="syncConfig()"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <template #icon>
 | 
				
			||||||
 | 
					                  <n-icon :component="Save" />
 | 
				
			||||||
 | 
					                </template>
 | 
				
			||||||
 | 
					              </n-button>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            This operation will restart all processes related. Service may interrupted for some while.
 | 
				
			||||||
 | 
					          </n-tooltip>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </n-modal>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { NButton, NCode, NIcon, NModal, NTooltip, useMessage } from "naive-ui"
 | 
				
			||||||
 | 
					import { CloudUpload, Edit, Save } from "@vicons/carbon"
 | 
				
			||||||
 | 
					import { ref } from "vue"
 | 
				
			||||||
 | 
					import { VueMonacoEditor } from "@guolao/vue-monaco-editor"
 | 
				
			||||||
 | 
					import * as yaml from "js-yaml"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const message = useMessage()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const props = defineProps<{ id: string, rules: any[], upstreams: any[], processes: any[] }>()
 | 
				
			||||||
 | 
					const emits = defineEmits(["reload"])
 | 
				
			||||||
 | 
					const host = location.protocol + "//" + location.host
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const submitting = ref(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const publishing = ref(false)
 | 
				
			||||||
 | 
					const editing = ref(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const config = ref<string | null>(null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function editConfig() {
 | 
				
			||||||
 | 
					  const resp = await fetch(`/cgi/sites/cfg/${props.id}`)
 | 
				
			||||||
 | 
					  config.value = await resp.text()
 | 
				
			||||||
 | 
					  editing.value = true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function syncConfig() {
 | 
				
			||||||
 | 
					  let content
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    content = yaml.load(config.value)
 | 
				
			||||||
 | 
					  } catch (e: any) {
 | 
				
			||||||
 | 
					    message.warning(`Your configuration has some issue: ${e.message}`)
 | 
				
			||||||
 | 
					    return
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  submitting.value = true
 | 
				
			||||||
 | 
					  const resp = await fetch(`/webhooks/sync/${props.id}`, {
 | 
				
			||||||
 | 
					    method: "PUT",
 | 
				
			||||||
 | 
					    headers: { "Content-Type": "application/json" },
 | 
				
			||||||
 | 
					    body: JSON.stringify(content)
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  if (resp.status != 200) {
 | 
				
			||||||
 | 
					    message.error(`Something went wrong... ${await resp.text()}`)
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    emits("reload")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  submitting.value = false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					.fab {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  bottom: 16px;
 | 
				
			||||||
 | 
					  right: 24px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										110
									
								
								pkg/sideload/view/src/components/data/sites-table-add.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								pkg/sideload/view/src/components/data/sites-table-add.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div>
 | 
				
			||||||
 | 
					    <n-button circle size="small" type="primary" @click="creating = true">
 | 
				
			||||||
 | 
					      <template #icon>
 | 
				
			||||||
 | 
					        <n-icon :component="Add" />
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					    </n-button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <n-modal
 | 
				
			||||||
 | 
					      v-model:show="creating"
 | 
				
			||||||
 | 
					      class="w-[720px]"
 | 
				
			||||||
 | 
					      content-style="padding: 0"
 | 
				
			||||||
 | 
					      preset="card"
 | 
				
			||||||
 | 
					      title="Create Site"
 | 
				
			||||||
 | 
					      segmented
 | 
				
			||||||
 | 
					      closable
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <div class="py-4 px-5 border border-solid border-b border-[#eee]">
 | 
				
			||||||
 | 
					        <n-input
 | 
				
			||||||
 | 
					          v-model:value="data.id"
 | 
				
			||||||
 | 
					          placeholder="Will be the file name of this file"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div class="relative mt-[4px] h-[540px]">
 | 
				
			||||||
 | 
					        <vue-monaco-editor
 | 
				
			||||||
 | 
					          v-model:value="data.content"
 | 
				
			||||||
 | 
					          :options="{ automaticLayout: true, minimap: { enabled: false } }"
 | 
				
			||||||
 | 
					          language="yaml"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="fab">
 | 
				
			||||||
 | 
					          <n-tooltip placement="left">
 | 
				
			||||||
 | 
					            <template #trigger>
 | 
				
			||||||
 | 
					              <n-button
 | 
				
			||||||
 | 
					                circle
 | 
				
			||||||
 | 
					                type="primary"
 | 
				
			||||||
 | 
					                size="large"
 | 
				
			||||||
 | 
					                class="shadow-lg"
 | 
				
			||||||
 | 
					                :loading="submitting"
 | 
				
			||||||
 | 
					                @click="submit()"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <template #icon>
 | 
				
			||||||
 | 
					                  <n-icon :component="Checkmark" />
 | 
				
			||||||
 | 
					                </template>
 | 
				
			||||||
 | 
					              </n-button>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            This operation will publish this site right away.
 | 
				
			||||||
 | 
					          </n-tooltip>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </n-modal>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { NButton, NIcon, NInput, NModal, NTooltip, useMessage } from "naive-ui"
 | 
				
			||||||
 | 
					import { Add, Checkmark } from "@vicons/carbon"
 | 
				
			||||||
 | 
					import { VueMonacoEditor } from "@guolao/vue-monaco-editor"
 | 
				
			||||||
 | 
					import { ref } from "vue"
 | 
				
			||||||
 | 
					import * as yaml from "js-yaml"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const message = useMessage()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const emits = defineEmits(["reload"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const submitting = ref(false)
 | 
				
			||||||
 | 
					const creating = ref(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const data = ref<any>({})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function submit() {
 | 
				
			||||||
 | 
					  let content
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    content = yaml.load(data.value.content)
 | 
				
			||||||
 | 
					  } catch (e: any) {
 | 
				
			||||||
 | 
					    message.warning(`Your configuration has some issue: ${e.message}`)
 | 
				
			||||||
 | 
					    return
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  submitting.value = true
 | 
				
			||||||
 | 
					  const resp = await fetch(`/webhooks/sync/${data.value.id}`, {
 | 
				
			||||||
 | 
					    method: "PUT",
 | 
				
			||||||
 | 
					    headers: { "Content-Type": "application/json" },
 | 
				
			||||||
 | 
					    body: JSON.stringify(content)
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  if (resp.status != 200) {
 | 
				
			||||||
 | 
					    message.error(`Something went wrong... ${await resp.text()}`)
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    reset()
 | 
				
			||||||
 | 
					    emits("reload")
 | 
				
			||||||
 | 
					    message.success("Your site has been created! 🎉")
 | 
				
			||||||
 | 
					    creating.value = false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  submitting.value = false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function reset() {
 | 
				
			||||||
 | 
					  data.value.id = ""
 | 
				
			||||||
 | 
					  data.value.content = ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					.fab {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  bottom: 16px;
 | 
				
			||||||
 | 
					  right: 24px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										36
									
								
								pkg/sideload/view/src/components/data/sites-table-expand.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								pkg/sideload/view/src/components/data/sites-table-expand.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="flex flex-col gap-1">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <div class="font-bold">Rules</div>
 | 
				
			||||||
 | 
					      <n-code :hljs="hljs" :code="parseData(props.rules)" language="json" />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <div class="font-bold">Upstreams</div>
 | 
				
			||||||
 | 
					      <n-code :hljs="hljs" :code="parseData(props.upstreams)" language="json" />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <div class="font-bold">Processes</div>
 | 
				
			||||||
 | 
					      <n-code :hljs="hljs" :code="parseData(props.processes)" language="json" />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { NCode } from "naive-ui"
 | 
				
			||||||
 | 
					import hljs from "highlight.js/lib/core"
 | 
				
			||||||
 | 
					import json from "highlight.js/lib/languages/json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hljs.registerLanguage("json", json)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const props = defineProps<{ rules: any[], upstreams: any[], processes: any[] }>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function parseData(data: any): string {
 | 
				
			||||||
 | 
					  return JSON.stringify(data, null, 1)
 | 
				
			||||||
 | 
					    .replace(/  +/g, " ")
 | 
				
			||||||
 | 
					    .replace(/\n/g, "")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
							
								
								
									
										76
									
								
								pkg/sideload/view/src/components/data/sites-table.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								pkg/sideload/view/src/components/data/sites-table.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div>
 | 
				
			||||||
 | 
					    <n-card title="Sites">
 | 
				
			||||||
 | 
					      <template #header-extra>
 | 
				
			||||||
 | 
					        <sites-table-add @reload="readSites()" />
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <n-data-table
 | 
				
			||||||
 | 
					        :columns="columns"
 | 
				
			||||||
 | 
					        :data="data"
 | 
				
			||||||
 | 
					        :row-key="(row: any) => row.id"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </n-card>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { NCard, NDataTable, NTag } from "naive-ui"
 | 
				
			||||||
 | 
					import { h, ref } from "vue"
 | 
				
			||||||
 | 
					import SitesTableExpand from "@/components/data/sites-table-expand.vue"
 | 
				
			||||||
 | 
					import SitesTableAction from "@/components/data/sites-table-action.vue"
 | 
				
			||||||
 | 
					import SitesTableAdd from "@/components/data/sites-table-add.vue"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const columns = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    type: "expand",
 | 
				
			||||||
 | 
					    renderExpand(row: any) {
 | 
				
			||||||
 | 
					      return h(SitesTableExpand, { ...row, class: "pl-[38px]" })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    title: "ID",
 | 
				
			||||||
 | 
					    key: "id",
 | 
				
			||||||
 | 
					    render(row: any) {
 | 
				
			||||||
 | 
					      return h(NTag, { type: "info", bordered: false, size: "small" }, row?.id)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    title: "Rules",
 | 
				
			||||||
 | 
					    key: "rules",
 | 
				
			||||||
 | 
					    render(row: any) {
 | 
				
			||||||
 | 
					      return row?.rules?.length ?? 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    title: "Upstreams",
 | 
				
			||||||
 | 
					    key: "upstreams",
 | 
				
			||||||
 | 
					    render(row: any) {
 | 
				
			||||||
 | 
					      return row?.upstreams?.length ?? 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    title: "Processes",
 | 
				
			||||||
 | 
					    key: "processes",
 | 
				
			||||||
 | 
					    render(row: any) {
 | 
				
			||||||
 | 
					      return row?.processes?.length ?? 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    title: "Actions",
 | 
				
			||||||
 | 
					    key: "actions",
 | 
				
			||||||
 | 
					    render(row: any) {
 | 
				
			||||||
 | 
					      return h(SitesTableAction, { ...row, onReload: () => readSites() })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const data = ref<any[]>([])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function readSites() {
 | 
				
			||||||
 | 
					  const resp = await fetch("/cgi/sites")
 | 
				
			||||||
 | 
					  data.value = await resp.json()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					readSites()
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
							
								
								
									
										60
									
								
								pkg/sideload/view/src/layouts/main.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								pkg/sideload/view/src/layouts/main.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <n-layout>
 | 
				
			||||||
 | 
					    <n-layout-header class="header py-[8px] px-[36px]" bordered>
 | 
				
			||||||
 | 
					      <div class="flex items-center gap-2">
 | 
				
			||||||
 | 
					        <router-link class="link" to="/">
 | 
				
			||||||
 | 
					          RoadSign<i>!</i>
 | 
				
			||||||
 | 
					        </router-link>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div class="nav-menu">
 | 
				
			||||||
 | 
					        <div class="h-full flex items-center header-nav">
 | 
				
			||||||
 | 
					          <n-menu v-model:value="key" :options="options" mode="horizontal" />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </n-layout-header>
 | 
				
			||||||
 | 
					    <n-layout-content class="h-[calc(100vh-70px)] container mx-auto" content-style="padding: 24px">
 | 
				
			||||||
 | 
					      <router-view />
 | 
				
			||||||
 | 
					    </n-layout-content>
 | 
				
			||||||
 | 
					  </n-layout>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { type MenuOption, NIcon, NLayout, NLayoutContent, NLayoutHeader, NMenu } from "naive-ui"
 | 
				
			||||||
 | 
					import { type Component, h, ref } from "vue"
 | 
				
			||||||
 | 
					import { Dashboard } from "@vicons/carbon"
 | 
				
			||||||
 | 
					import { RouterLink, useRoute, useRouter } from "vue-router"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const route = useRoute()
 | 
				
			||||||
 | 
					const router = useRouter()
 | 
				
			||||||
 | 
					const key = ref(route.name?.toString())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.afterEach((to) => {
 | 
				
			||||||
 | 
					  key.value = to.name?.toString() ?? "index"
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const options: MenuOption[] = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    label: () => h(RouterLink, { to: { name: "dashboard" } }, "Dashboard"),
 | 
				
			||||||
 | 
					    icon: renderIcon(Dashboard),
 | 
				
			||||||
 | 
					    key: "dashboard"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function renderIcon(icon: Component) {
 | 
				
			||||||
 | 
					  return () => h(NIcon, null, { default: () => h(icon) })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					.header {
 | 
				
			||||||
 | 
					  display: grid;
 | 
				
			||||||
 | 
					  grid-template-columns: 1fr auto 1fr;
 | 
				
			||||||
 | 
					  gap: 40px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.link {
 | 
				
			||||||
 | 
					  all: unset;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										16
									
								
								pkg/sideload/view/src/main.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								pkg/sideload/view/src/main.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					import "./assets/main.css"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "virtual:uno.css"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { createApp } from "vue"
 | 
				
			||||||
 | 
					import { createPinia } from "pinia"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import root from "./root.vue"
 | 
				
			||||||
 | 
					import router from "./router"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const app = createApp(root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					app.use(createPinia())
 | 
				
			||||||
 | 
					app.use(router)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					app.mount("#app")
 | 
				
			||||||
							
								
								
									
										9
									
								
								pkg/sideload/view/src/root.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								pkg/sideload/view/src/root.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <n-message-provider>
 | 
				
			||||||
 | 
					    <router-view />
 | 
				
			||||||
 | 
					  </n-message-provider>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { NMessageProvider } from "naive-ui"
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
							
								
								
									
										21
									
								
								pkg/sideload/view/src/router/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								pkg/sideload/view/src/router/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import { createRouter, createWebHistory } from "vue-router"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const router = createRouter({
 | 
				
			||||||
 | 
					  history: createWebHistory(import.meta.env.BASE_URL),
 | 
				
			||||||
 | 
					  routes: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      path: "/",
 | 
				
			||||||
 | 
					      name: "layouts.main",
 | 
				
			||||||
 | 
					      component: () => import("@/layouts/main.vue"),
 | 
				
			||||||
 | 
					      children: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          path: "/",
 | 
				
			||||||
 | 
					          name: "dashboard",
 | 
				
			||||||
 | 
					          component: () => import("@/views/dashboard.vue")
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default router
 | 
				
			||||||
							
								
								
									
										35
									
								
								pkg/sideload/view/src/views/dashboard.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								pkg/sideload/view/src/views/dashboard.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="flex flex-col gap-2">
 | 
				
			||||||
 | 
					    <div class="grid gap-2 grid-cols-2 lg:grid-cols-4">
 | 
				
			||||||
 | 
					      <n-card embedded>
 | 
				
			||||||
 | 
					        <n-statistic label="Status">{{ data?.status ? "Operational" : "Incident" }}</n-statistic>
 | 
				
			||||||
 | 
					      </n-card>
 | 
				
			||||||
 | 
					      <n-card embedded>
 | 
				
			||||||
 | 
					        <n-statistic label="Sites">{{ data?.sites }}</n-statistic>
 | 
				
			||||||
 | 
					      </n-card>
 | 
				
			||||||
 | 
					      <n-card embedded>
 | 
				
			||||||
 | 
					        <n-statistic label="Upstreams">{{ data?.upstreams }}</n-statistic>
 | 
				
			||||||
 | 
					      </n-card>
 | 
				
			||||||
 | 
					      <n-card embedded>
 | 
				
			||||||
 | 
					        <n-statistic label="Processes">{{ data?.processes }}</n-statistic>
 | 
				
			||||||
 | 
					      </n-card>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <sites-table />
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { NCard, NStatistic } from "naive-ui"
 | 
				
			||||||
 | 
					import { ref } from "vue"
 | 
				
			||||||
 | 
					import SitesTable from "@/components/data/sites-table.vue"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const data = ref<any>({})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function readStatistics() {
 | 
				
			||||||
 | 
					  const resp = await fetch("/cgi/statistics")
 | 
				
			||||||
 | 
					  data.value = await resp.json()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					readStatistics()
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
							
								
								
									
										13
									
								
								pkg/sideload/view/tsconfig.app.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								pkg/sideload/view/tsconfig.app.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "extends": "@vue/tsconfig/tsconfig.dom.json",
 | 
				
			||||||
 | 
					  "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
 | 
				
			||||||
 | 
					  "exclude": ["src/**/__tests__/*"],
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "composite": true,
 | 
				
			||||||
 | 
					    "noEmit": true,
 | 
				
			||||||
 | 
					    "baseUrl": ".",
 | 
				
			||||||
 | 
					    "paths": {
 | 
				
			||||||
 | 
					      "@/*": ["./src/*"]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								pkg/sideload/view/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								pkg/sideload/view/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "files": [],
 | 
				
			||||||
 | 
					  "references": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "path": "./tsconfig.node.json"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "path": "./tsconfig.app.json"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								pkg/sideload/view/tsconfig.node.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								pkg/sideload/view/tsconfig.node.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "extends": "@tsconfig/node18/tsconfig.json",
 | 
				
			||||||
 | 
					  "include": [
 | 
				
			||||||
 | 
					    "vite.config.*",
 | 
				
			||||||
 | 
					    "vitest.config.*",
 | 
				
			||||||
 | 
					    "cypress.config.*",
 | 
				
			||||||
 | 
					    "nightwatch.conf.*",
 | 
				
			||||||
 | 
					    "playwright.config.*"
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "composite": true,
 | 
				
			||||||
 | 
					    "noEmit": true,
 | 
				
			||||||
 | 
					    "module": "ESNext",
 | 
				
			||||||
 | 
					    "moduleResolution": "Bundler",
 | 
				
			||||||
 | 
					    "types": ["node"]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								pkg/sideload/view/unocss.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								pkg/sideload/view/unocss.config.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					import { defineConfig, presetUno } from "unocss"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineConfig({
 | 
				
			||||||
 | 
					  presets: [presetUno({ preflight: false })]
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										24
									
								
								pkg/sideload/view/vite.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								pkg/sideload/view/vite.config.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					import { fileURLToPath, URL } from "node:url"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { defineConfig } from "vite"
 | 
				
			||||||
 | 
					import vue from "@vitejs/plugin-vue"
 | 
				
			||||||
 | 
					import unocss from "unocss/vite"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://vitejs.dev/config/
 | 
				
			||||||
 | 
					export default defineConfig({
 | 
				
			||||||
 | 
					  plugins: [
 | 
				
			||||||
 | 
					    vue(),
 | 
				
			||||||
 | 
					    unocss()
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  resolve: {
 | 
				
			||||||
 | 
					    alias: {
 | 
				
			||||||
 | 
					      "@": fileURLToPath(new URL("./src", import.meta.url))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  server: {
 | 
				
			||||||
 | 
					    proxy: {
 | 
				
			||||||
 | 
					      "/webhooks": "http://127.0.0.1:81",
 | 
				
			||||||
 | 
					      "/cgi": "http://127.0.0.1:81"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										2904
									
								
								pkg/sideload/view/yarn.lock
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2904
									
								
								pkg/sideload/view/yarn.lock
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -2,12 +2,25 @@ package sign
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/samber/lo"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/exec"
 | 
						"os/exec"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ProcessConfig struct {
 | 
					type ProcessStatus = int8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ProcessCreated = ProcessStatus(iota)
 | 
				
			||||||
 | 
						ProcessStarting
 | 
				
			||||||
 | 
						ProcessStarted
 | 
				
			||||||
 | 
						ProcessExited
 | 
				
			||||||
 | 
						ProcessFailure
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ProcessInstance struct {
 | 
				
			||||||
	ID          string     `json:"id" yaml:"id"`
 | 
						ID          string     `json:"id" yaml:"id"`
 | 
				
			||||||
	Workdir     string     `json:"workdir" yaml:"workdir"`
 | 
						Workdir     string     `json:"workdir" yaml:"workdir"`
 | 
				
			||||||
	Command     []string   `json:"command" yaml:"command"`
 | 
						Command     []string   `json:"command" yaml:"command"`
 | 
				
			||||||
@@ -15,10 +28,14 @@ type ProcessConfig struct {
 | 
				
			|||||||
	Prepares    [][]string `json:"prepares" yaml:"prepares"`
 | 
						Prepares    [][]string `json:"prepares" yaml:"prepares"`
 | 
				
			||||||
	Preheat     bool       `json:"preheat" yaml:"preheat"`
 | 
						Preheat     bool       `json:"preheat" yaml:"preheat"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Cmd *exec.Cmd `json:"-"`
 | 
						Cmd    *exec.Cmd       `json:"-"`
 | 
				
			||||||
 | 
						Logger strings.Builder `json:"-"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Status ProcessStatus `json:"status"`
 | 
				
			||||||
 | 
						Logs   string        `json:"logs"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (v *ProcessConfig) BootProcess() error {
 | 
					func (v *ProcessInstance) BootProcess() error {
 | 
				
			||||||
	if v.Cmd != nil {
 | 
						if v.Cmd != nil {
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -43,7 +60,7 @@ func (v *ProcessConfig) BootProcess() error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (v *ProcessConfig) PrepareProcess() error {
 | 
					func (v *ProcessInstance) PrepareProcess() error {
 | 
				
			||||||
	for _, script := range v.Prepares {
 | 
						for _, script := range v.Prepares {
 | 
				
			||||||
		if len(script) <= 0 {
 | 
							if len(script) <= 0 {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
@@ -57,7 +74,7 @@ func (v *ProcessConfig) PrepareProcess() error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (v *ProcessConfig) StartProcess() error {
 | 
					func (v *ProcessInstance) StartProcess() error {
 | 
				
			||||||
	if len(v.Command) <= 0 {
 | 
						if len(v.Command) <= 0 {
 | 
				
			||||||
		return fmt.Errorf("you need set the command for %s to enable process manager", v.ID)
 | 
							return fmt.Errorf("you need set the command for %s to enable process manager", v.ID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -65,11 +82,28 @@ func (v *ProcessConfig) StartProcess() error {
 | 
				
			|||||||
	v.Cmd = exec.Command(v.Command[0], v.Command[1:]...)
 | 
						v.Cmd = exec.Command(v.Command[0], v.Command[1:]...)
 | 
				
			||||||
	v.Cmd.Dir = filepath.Join(v.Workdir)
 | 
						v.Cmd.Dir = filepath.Join(v.Workdir)
 | 
				
			||||||
	v.Cmd.Env = append(v.Cmd.Env, v.Environment...)
 | 
						v.Cmd.Env = append(v.Cmd.Env, v.Environment...)
 | 
				
			||||||
 | 
						v.Cmd.Stdout = &v.Logger
 | 
				
			||||||
 | 
						v.Cmd.Stderr = &v.Logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Monitor
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							for {
 | 
				
			||||||
 | 
								if v.Cmd.Process == nil || v.Cmd.ProcessState == nil {
 | 
				
			||||||
 | 
									v.Status = ProcessStarting
 | 
				
			||||||
 | 
								} else if !v.Cmd.ProcessState.Exited() {
 | 
				
			||||||
 | 
									v.Status = ProcessStarted
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									v.Status = lo.Ternary(v.Cmd.ProcessState.Success(), ProcessExited, ProcessFailure)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								time.Sleep(100 * time.Millisecond)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return v.Cmd.Start()
 | 
						return v.Cmd.Start()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (v *ProcessConfig) StopProcess() error {
 | 
					func (v *ProcessInstance) StopProcess() error {
 | 
				
			||||||
	if v.Cmd != nil && v.Cmd.Process != nil {
 | 
						if v.Cmd != nil && v.Cmd.Process != nil {
 | 
				
			||||||
		if err := v.Cmd.Process.Signal(os.Interrupt); err != nil {
 | 
							if err := v.Cmd.Process.Signal(os.Interrupt); err != nil {
 | 
				
			||||||
			v.Cmd.Process.Kill()
 | 
								v.Cmd.Process.Kill()
 | 
				
			||||||
@@ -82,8 +116,13 @@ func (v *ProcessConfig) StopProcess() error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (v *ProcessInstance) GetLogs() string {
 | 
				
			||||||
 | 
						v.Logs = v.Logger.String()
 | 
				
			||||||
 | 
						return v.Logs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (v *RoadApp) PreheatProcesses(callbacks ...func(total int, success int)) {
 | 
					func (v *RoadApp) PreheatProcesses(callbacks ...func(total int, success int)) {
 | 
				
			||||||
	var processes []*ProcessConfig
 | 
						var processes []*ProcessInstance
 | 
				
			||||||
	for _, site := range v.Sites {
 | 
						for _, site := range v.Sites {
 | 
				
			||||||
		for _, process := range site.Processes {
 | 
							for _, process := range site.Processes {
 | 
				
			||||||
			if process.Preheat {
 | 
								if process.Preheat {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,7 @@ import (
 | 
				
			|||||||
	"github.com/valyala/fasthttp"
 | 
						"github.com/valyala/fasthttp"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func makeHypertextResponse(c *fiber.Ctx, upstream *UpstreamConfig) error {
 | 
					func makeHypertextResponse(c *fiber.Ctx, upstream *UpstreamInstance) error {
 | 
				
			||||||
	timeout := time.Duration(viper.GetInt64("performance.network_timeout")) * time.Millisecond
 | 
						timeout := time.Duration(viper.GetInt64("performance.network_timeout")) * time.Millisecond
 | 
				
			||||||
	return proxy.Do(c, upstream.MakeURI(c), &fasthttp.Client{
 | 
						return proxy.Do(c, upstream.MakeURI(c), &fasthttp.Client{
 | 
				
			||||||
		ReadTimeout:  timeout,
 | 
							ReadTimeout:  timeout,
 | 
				
			||||||
@@ -26,7 +26,7 @@ func makeHypertextResponse(c *fiber.Ctx, upstream *UpstreamConfig) error {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func makeFileResponse(c *fiber.Ctx, upstream *UpstreamConfig) error {
 | 
					func makeFileResponse(c *fiber.Ctx, upstream *UpstreamInstance) error {
 | 
				
			||||||
	uri, queries := upstream.GetRawURI()
 | 
						uri, queries := upstream.GetRawURI()
 | 
				
			||||||
	root := http.Dir(uri)
 | 
						root := http.Dir(uri)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,13 +44,13 @@ type RequestTransformerConfig = transformers.RequestTransformerConfig
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type SiteConfig struct {
 | 
					type SiteConfig struct {
 | 
				
			||||||
	ID           string                      `json:"id"`
 | 
						ID           string                      `json:"id"`
 | 
				
			||||||
	Rules        []*RouterRuleConfig         `json:"rules" yaml:"rules"`
 | 
						Rules        []*RouterRule               `json:"rules" yaml:"rules"`
 | 
				
			||||||
	Transformers []*RequestTransformerConfig `json:"transformers" yaml:"transformers"`
 | 
						Transformers []*RequestTransformerConfig `json:"transformers" yaml:"transformers"`
 | 
				
			||||||
	Upstreams    []*UpstreamConfig           `json:"upstreams" yaml:"upstreams"`
 | 
						Upstreams    []*UpstreamInstance         `json:"upstreams" yaml:"upstreams"`
 | 
				
			||||||
	Processes    []*ProcessConfig            `json:"processes" yaml:"processes"`
 | 
						Processes    []*ProcessInstance          `json:"processes" yaml:"processes"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RouterRuleConfig struct {
 | 
					type RouterRule struct {
 | 
				
			||||||
	Host    []string            `json:"host" yaml:"host"`
 | 
						Host    []string            `json:"host" yaml:"host"`
 | 
				
			||||||
	Path    []string            `json:"path" yaml:"path"`
 | 
						Path    []string            `json:"path" yaml:"path"`
 | 
				
			||||||
	Queries map[string]string   `json:"queries" yaml:"queries"`
 | 
						Queries map[string]string   `json:"queries" yaml:"queries"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,12 +15,12 @@ const (
 | 
				
			|||||||
	UpstreamTypeUnknown   = "unknown"
 | 
						UpstreamTypeUnknown   = "unknown"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type UpstreamConfig struct {
 | 
					type UpstreamInstance struct {
 | 
				
			||||||
	ID  string `json:"id" yaml:"id"`
 | 
						ID  string `json:"id" yaml:"id"`
 | 
				
			||||||
	URI string `json:"uri" yaml:"uri"`
 | 
						URI string `json:"uri" yaml:"uri"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (v *UpstreamConfig) GetType() string {
 | 
					func (v *UpstreamInstance) GetType() string {
 | 
				
			||||||
	protocol := strings.SplitN(v.URI, "://", 2)[0]
 | 
						protocol := strings.SplitN(v.URI, "://", 2)[0]
 | 
				
			||||||
	switch protocol {
 | 
						switch protocol {
 | 
				
			||||||
	case "file", "files":
 | 
						case "file", "files":
 | 
				
			||||||
@@ -32,7 +32,7 @@ func (v *UpstreamConfig) GetType() string {
 | 
				
			|||||||
	return UpstreamTypeUnknown
 | 
						return UpstreamTypeUnknown
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (v *UpstreamConfig) GetRawURI() (string, url.Values) {
 | 
					func (v *UpstreamInstance) GetRawURI() (string, url.Values) {
 | 
				
			||||||
	uri := strings.SplitN(v.URI, "://", 2)[1]
 | 
						uri := strings.SplitN(v.URI, "://", 2)[1]
 | 
				
			||||||
	data := strings.SplitN(uri, "?", 2)
 | 
						data := strings.SplitN(uri, "?", 2)
 | 
				
			||||||
	data = append(data, " ") // Make data array least have two element
 | 
						data = append(data, " ") // Make data array least have two element
 | 
				
			||||||
@@ -41,7 +41,7 @@ func (v *UpstreamConfig) GetRawURI() (string, url.Values) {
 | 
				
			|||||||
	return data[0], qs
 | 
						return data[0], qs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (v *UpstreamConfig) MakeURI(ctx *fiber.Ctx) string {
 | 
					func (v *UpstreamInstance) MakeURI(ctx *fiber.Ctx) string {
 | 
				
			||||||
	var queries []string
 | 
						var queries []string
 | 
				
			||||||
	for k, v := range ctx.Queries() {
 | 
						for k, v := range ctx.Queries() {
 | 
				
			||||||
		parsed, _ := url.QueryUnescape(v)
 | 
							parsed, _ := url.QueryUnescape(v)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user