Browse Source

1、feat: 增加wails 打包成桌面应用,打包成功,可以

tuon 1 year ago
parent
commit
ae3d2eba74

BIN
build/bin/nginx-ui-desktop-dev.exe


BIN
build/bin/nginx-ui-dev.exe


+ 35 - 0
conf/app.conf

@@ -0,0 +1,35 @@
+appname = server
+httpport = 8080
+runmode = dev
+copyrequestbody = true
+
+baseApi = /nginx-ui/api
+contextpath = /nginx-ui
+
+datadir = ./data
+dbdir = ./data/db
+nginxPath = /usr/sbin/nginx
+nginxDir = /etc/nginx
+
+admin_password = admin123
+reset_admin_password = true
+
+sessionon = true
+sessionprovider = file
+sessionname = nginx_session
+sessiongcmaxlifetime = 7200
+sessionproviderconfig = "./data/sessions"
+
+thirdsessionenable = false
+thirdsessionname =
+thirdsessioncheckurl =
+
+
+oauth2_client_id =
+oauth2_client_secret =
+oauth2_authorize_endpoint =
+oauth2_token_endpoint =
+oauth2_redirect_uri =
+oauth2_scopes = ""
+oauth2_userinfo =
+oauth2_enable = false

BIN
data/db/sqlite.db


+ 31 - 23
desktop/api.go

@@ -11,6 +11,7 @@ import (
 var ApiSession = Session{}
 
 var userService = service.NewUserService()
+var nginxApi = NewNginxApi()
 
 // Api struct
 type Api struct {
@@ -27,64 +28,71 @@ func NewApi() *Api {
 func (a *Api) Startup(ctx context.Context) {
 	ApiSession.ctx = ctx
 	a.ctx = ctx
-
+	ApiSession.Load()
+	logs.Info("Startup finish")
 }
 
 type ApiResp struct {
-	Data models.RespData `json:"data"`
+	Data *models.RespData `json:"data"`
 }
 
 // PostApi 做一个统一的适配层
 func (a *Api) PostApi(path string, req string) ApiResp {
-	logs.Info("path: %s, data: %s", path, req)
-	var data models.RespData
+	logs.Info("[POST] path: %s, data: %s", path, req)
+
+	if nginxApi.Match(path) {
+		return nginxApi.PostApi(path, req)
+	}
+	var data *models.RespData
+
 	switch path {
 	case "/user/login":
-		var user models.User
-		err := json.Unmarshal([]byte(req), &user)
+		var user *models.User
+		err := json.Unmarshal([]byte(req), user)
 		if err != nil {
 			logs.Error(err, req)
 			data = models.NewErrorResp(err)
 		}
 		data = userService.Login(user)
+		if data.Success() {
+			ApiSession.SetUser(user)
+		}
 		break
-	case "/user/info":
+	case "/user/register":
+		data = userService.SignUp([]byte(req))
 		break
 	}
 	return ApiResp{Data: data}
 }
 
 func (a *Api) GetApi(path string, req string) ApiResp {
-	logs.Info("path: %s, data: %s", path, req)
-	var data models.RespData
+	logs.Info("[GET] path: %s, data: %s", path, req)
+	if nginxApi.Match(path) {
+		return nginxApi.GetApi(path, req)
+	}
+	var data *models.RespData
 	switch path {
 	case "/user/info":
 		data = models.SuccessResp(ApiSession.user)
 		break
 	}
+
+	logs.Info("resp:{}", data)
 	return ApiResp{Data: data}
 }
 
 func (a *Api) DeleteApi(path string, req string) ApiResp {
-	logs.Info("path: %s, data: %s", path, req)
-	switch path {
-
-	case "/user/login":
-		break
-	case "/user/info":
-		break
+	logs.Info("[DELETE] path: %s, data: %s", path, req)
+	if nginxApi.Match(path) {
+		return nginxApi.DeleteApi(path, req)
 	}
 	return ApiResp{}
 }
 
 func (a *Api) PutApi(path string, req string) ApiResp {
-	logs.Info("path: %s, data: %s", path, req)
-	switch path {
-
-	case "/user/login":
-		break
-	case "/user/info":
-		break
+	logs.Info("[PUT] path: %s, data: %s", path, req)
+	if nginxApi.Match(path) {
+		return nginxApi.PutApi(path, req)
 	}
 	return ApiResp{}
 }

+ 42 - 0
desktop/handler.go

@@ -0,0 +1,42 @@
+package desktop
+
+import (
+	"context"
+	"github.com/astaxie/beego/logs"
+	"net/http"
+	"strings"
+)
+
+const prefix = "/api/nginx-ui/api"
+
+type ApiHandler struct {
+	http.Handler
+	ctx context.Context
+	api *Api
+}
+
+func NewApiHandler() *ApiHandler {
+	return &ApiHandler{
+		api: NewApi(),
+	}
+}
+
+func (h *ApiHandler) Startup(ctx context.Context) {
+	ApiSession.ctx = ctx
+	h.ctx = ctx
+	h.api.ctx = ctx
+
+}
+
+// 这也是一种方法,不过感觉比较复杂,需要自己处理请求参数之类的
+func (h *ApiHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
+	requestUrl := strings.TrimPrefix(req.URL.Path, prefix)
+	method := req.Method
+	switch method {
+
+	case http.MethodGet:
+
+	}
+	logs.Info("ServerHTTP: %s,%s", method, requestUrl)
+	res.Write([]byte("{}"))
+}

+ 82 - 0
desktop/nginx.go

@@ -0,0 +1,82 @@
+package desktop
+
+import (
+	"context"
+	"github.com/astaxie/beego/logs"
+	"nginx-ui/server/models"
+	"nginx-ui/server/routers"
+	"nginx-ui/server/service"
+	"strings"
+)
+
+var logger = logs.GetLogger("NginxApi")
+
+var nginxService = service.NginxService{}
+
+// NginxApi struct
+type NginxApi struct {
+	ctx context.Context
+}
+
+// NewNginxApi creates a new App application struct
+func NewNginxApi() *NginxApi {
+	return &NginxApi{}
+}
+
+func (a *NginxApi) Match(path string) bool {
+	return strings.HasPrefix(path, "/nginx")
+}
+
+// PostApi 做一个统一的适配层
+func (a *NginxApi) PostApi(path string, req string) ApiResp {
+	logger.Printf("[POST] path: %s, data: %s", path, req)
+	var user = ApiSession.user
+	if path == routers.NginxR {
+		return ApiResp{
+			Data: nginxService.Add(user, []byte(req)),
+		}
+	}
+
+	var data *models.RespData
+
+	if result := ParsePathParam(path, routers.NginxGetR); result.Match {
+		id := result.GetParam("id")
+		data = nginxService.GetNginx(id, user)
+	} else if result := ParsePathParam(path, routers.NginxStatusR); result.Match {
+		//id := result.GetParam("id")
+	}
+	return ApiResp{Data: data}
+}
+
+func (a *NginxApi) GetApi(path string, req string) ApiResp {
+	logger.Printf("[GET] path: %s, data: %s", path, req)
+	var user = ApiSession.user
+	if path == routers.NginxR {
+		return ApiResp{
+			Data: nginxService.ListNginx(user),
+		}
+	}
+	if r := ParsePathParam(path, routers.NginxGetR); r.Match {
+		id := r.GetParam("id")
+		logs.Info("param: ", r, id)
+		return ApiResp{
+			Data: nginxService.GetNginx(id, user),
+		}
+	}
+
+	var data *models.RespData
+
+	logs.Info("resp:{}", data)
+	return ApiResp{Data: data}
+}
+
+func (a *NginxApi) DeleteApi(path string, req string) ApiResp {
+	logger.Printf("[DELETE] path: %s, data: %s", path, req)
+
+	return ApiResp{}
+}
+
+func (a *NginxApi) PutApi(path string, req string) ApiResp {
+	logger.Printf("[PUT] path: %s, data: %s", path, req)
+	return ApiResp{}
+}

+ 35 - 0
desktop/session.go

@@ -2,7 +2,10 @@ package desktop
 
 import (
 	"context"
+	"encoding/json"
+	"fmt"
 	"nginx-ui/server/models"
+	"os"
 )
 
 type Session struct {
@@ -13,4 +16,36 @@ type Session struct {
 
 func (s *Session) SetUser(user *models.User) {
 	s.user = user
+	j, err := json.Marshal(user)
+	if err != nil {
+		fmt.Println("json fail", err)
+		return
+	}
+	err = os.MkdirAll("./data/sessions", 0666)
+	if err != nil {
+		fmt.Printf("mkdir dir fail: %s\n\n", err)
+		return
+	}
+	err = os.WriteFile("./data/sessions/local", j, 0666)
+	if err != nil {
+		fmt.Println("save session fail", err)
+	} else {
+		fmt.Printf("save session ok: %s\n", user.Account)
+	}
+}
+
+func (s *Session) Load() {
+	by, err := os.ReadFile("./data/sessions/local")
+	if err != nil {
+		fmt.Printf("session read fail: %s\n", err)
+		return
+	}
+	var user *models.User
+	err = json.Unmarshal(by, &user)
+	if err != nil {
+		fmt.Printf("session read fail: %s\n", err)
+		return
+	}
+	s.user = user
+	fmt.Printf("session load: %s\n", user.Account)
 }

+ 74 - 0
desktop/utils.go

@@ -0,0 +1,74 @@
+package desktop
+
+import (
+	"encoding/json"
+	"regexp"
+	"strings"
+)
+
+type MatchResult struct {
+	Params  map[string]string `json:"params"`
+	Match   bool              `json:"match"`
+	Origin  string            `json:"origin"`
+	Pattern string            `json:"pattern"`
+}
+
+func (r *MatchResult) String() string {
+	b, err := json.Marshal(r)
+	if err != nil {
+		return ""
+	}
+	return string(b)
+}
+
+func (r *MatchResult) GetParam(key string) string {
+	return r.Params[key]
+}
+
+func ParseKey(pattern string) string {
+	index := strings.Index(pattern, "/:")
+	if index < 0 || index > len(pattern)-2 {
+		return ""
+	}
+	str := pattern[index+1:]
+	end := strings.Index(str, "/")
+	if end == -1 {
+		end = len(str)
+	}
+	key := str[0:end]
+	return key
+}
+
+// ParsePathParam 解析路径中的 :id 字段
+func ParsePathParam(path string, pattern string) *MatchResult {
+
+	var result = &MatchResult{
+		Match:  false,
+		Params: map[string]string{},
+		Origin: path,
+	}
+	var keys []string
+	var reg = pattern
+	for i := 0; true; i++ {
+		key := ParseKey(reg)
+		if len(key) == 0 {
+			break
+		}
+		keys = append(keys, key[1:])
+		reg = strings.ReplaceAll(reg, key, "(.+)?")
+	}
+
+	result.Pattern = reg
+
+	compile := regexp.MustCompile(reg)
+	match := compile.FindStringSubmatch(path)
+	if len(match) < 1 {
+		return result
+	}
+	result.Match = true
+	for i := 1; i < len(match); i++ {
+		k := keys[i-1]
+		result.Params[k] = match[i]
+	}
+	return result
+}

+ 20 - 0
desktop/utils_test.go

@@ -0,0 +1,20 @@
+package desktop
+
+import (
+	"fmt"
+	"testing"
+)
+
+// 解析路径中的 :id 字段
+func TestParseId(t *testing.T) {
+
+	fmt.Println(ParsePathParam("/nginx/10", "/nginx/:id"))
+	fmt.Println(ParsePathParam("/nginx/1/refresh", "/nginx/:id/refresh"))
+	fmt.Println(ParsePathParam("/nginx/134/refresh", "/nginx/:id/refresh"))
+	fmt.Println(ParsePathParam("/nginx/125/http/refresh", "/nginx/:id/http/refresh"))
+	fmt.Println(ParsePathParam("/nginx/125/http/refresh", "/nginx/:id/http"))
+	fmt.Println(ParsePathParam("/nginx/125/admin/http/refresh", "/nginx/:id/:user/http/refresh"))
+
+	fmt.Println(ParsePathParam("/nginx/123/wew/789", "/nginx/:id"))
+
+}

File diff suppressed because it is too large
+ 0 - 8
frontend/dist/assets/index-154a1b67.js


+ 3 - 3
frontend/dist/index.html

@@ -1,10 +1,10 @@
 <!DOCTYPE html><html lang="en"><head>
     <meta charset="UTF-8">
-    <link rel="icon" type="image/svg+xml" href="/nginx-ui/vite.svg">
+    <link rel="icon" type="image/svg+xml" href="/vite.svg">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>NginxUI</title>
     <script type="application/javascript" src="./config.js"></script>
-    <script crossorigin="">import('/nginx-ui/assets/index-154a1b67.js').finally(() => {
+    <script crossorigin="">import('/assets/index-264e9fe8.js').finally(() => {
             
     const qiankunLifeCycle = window.moudleQiankunAppLifeCycles && window.moudleQiankunAppLifeCycles['nginx-ui'];
     if (qiankunLifeCycle) {
@@ -15,7 +15,7 @@
     }
   
           })</script>
-    <link rel="stylesheet" href="/nginx-ui/assets/index-49502c45.css">
+    <link rel="stylesheet" href="/assets/index-49502c45.css">
   </head>
   <body>
     <div id="nginx_ui_root"></div>

+ 1 - 0
frontend/package.json

@@ -11,6 +11,7 @@
   "scripts": {
     "dev": "vite",
     "build": "tsc && vite build --base=/nginx-ui/",
+    "desktop": "tsc && vite build --base=/",
     "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
     "preview": "vite preview"
   },

+ 1 - 1
frontend/package.json.md5

@@ -1 +1 @@
-7deb3a4e37e6d19d18e2428677450a23
+87f56136b1efe24b64fc6a9ab5e77599

+ 15 - 4
frontend/src/api/desktop.api.ts

@@ -1,6 +1,17 @@
 import {AxiosInstance, AxiosRequestConfig} from 'axios'
 import {isDesktop} from "../config/consts.ts";
 import * as DesktopApi from "../../wailsjs/go/desktop/Api";
+import {store} from "../store";
+import {UserActions} from "../store/slice/user.ts";
+import {desktop} from "../../wailsjs/go/models.ts";
+
+
+const checkResp = (resp: desktop.ApiResp) => {
+    if (resp.data?.code == 401){
+        store.dispatch(UserActions.clearUser())
+    }
+    return resp
+}
 
 // @ts-ignore
 export const checkDesktopApi = (request: AxiosInstance)=>{
@@ -10,18 +21,18 @@ export const checkDesktopApi = (request: AxiosInstance)=>{
     // @ts-ignore
     request.get = (url: string, config: AxiosRequestConfig<any>)=> {
         const data = config?.params ? JSON.stringify(config.params) : "{}"
-        return DesktopApi.GetApi(url, data)
+        return DesktopApi.GetApi(url, data).then(res=>checkResp(res))
     }
     // @ts-ignore
     request.post = (url: string, data?: any, config?: AxiosRequestConfig<any>) =>{
-        return DesktopApi.PostApi(url, data? JSON.stringify(data): "{}")
+        return DesktopApi.PostApi(url, data? JSON.stringify(data): "{}").then(res=>checkResp(res))
     }
     // @ts-ignore
     request.delete = (url: string, config?: AxiosRequestConfig<any>) => {
-        return DesktopApi.DeleteApi(url, config?.data?JSON.stringify(config.data):"{}")
+        return DesktopApi.DeleteApi(url, config?.data?JSON.stringify(config.data):"{}").then(res=>checkResp(res))
     }
     // @ts-ignore
     request.put = (url: string, data?: any, config?: AxiosRequestConfig<any>) => {
-        return DesktopApi.PutApi(url, data ? JSON.stringify(data): "{}")
+        return DesktopApi.PutApi(url, data ? JSON.stringify(data): "{}").then(res=>checkResp(res))
     }
 }

+ 1 - 1
frontend/wailsjs/go/models.ts

@@ -1,7 +1,7 @@
 export namespace desktop {
 	
 	export class ApiResp {
-	    data: models.RespData;
+	    data?: models.RespData;
 	
 	    static createFrom(source: any = {}) {
 	        return new ApiResp(source);

+ 3 - 0
main.go

@@ -24,6 +24,9 @@ func main() {
 		Height: 768,
 		AssetServer: &assetserver.Options{
 			Assets: assets,
+			//如果你想为你的前端动态加载或生成资产,你可以使用 AssetsHandler 选项 来实现。
+			//AssetsHandler 是一个通用的 http.Handler,对于资产服务器上的任何非 GET 请求以及由于找不到文件而无法从捆绑资产提供服务的 GET 请求,都会调用它。
+			//Handler: desktop.NewApiHandler(),
 		},
 		BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
 		OnStartup:        api.Startup,

+ 4 - 15
server/controllers/user.go

@@ -21,8 +21,8 @@ func NewUserController() *UserController {
 
 // Login 登录
 func (c *UserController) Login() {
-	var user models.User
-	err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
+	var user *models.User
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, user)
 	if err != nil {
 		logs.Error(err, string(c.Ctx.Input.RequestBody))
 		c.ErrorJson(err)
@@ -45,17 +45,6 @@ func (c *UserController) User() {
 
 // Register 用户注册
 func (c *UserController) Register() {
-	var user models.User
-	err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
-	if err != nil {
-		logs.Error(err, string(c.Ctx.Input.RequestBody))
-		c.ErrorJson(err)
-		return
-	}
-
-	if err != nil {
-		c.ErrorJson(err)
-		return
-	}
-	c.setMsg("注册成功!").json()
+	resp := c.service.SignUp(c.Ctx.Input.RequestBody)
+	c.postJson(resp)
 }

+ 2 - 1
server/init/init.go

@@ -2,6 +2,7 @@ package init
 
 import (
 	"encoding/gob"
+	"fmt"
 	"nginx-ui/server/config"
 	"nginx-ui/server/db"
 	"nginx-ui/server/models"
@@ -11,5 +12,5 @@ func init() {
 	gob.Register(models.User{})
 	db.Init()
 	config.InitAdmin()
-	println("init success")
+	fmt.Println("init success")
 }

+ 22 - 6
server/models/resp.go

@@ -15,26 +15,42 @@ func (r *RespData) SetCode(code int) *RespData {
 	return r
 }
 
-func SuccessResp(data interface{}) RespData {
-	return RespData{
+func (r *RespData) SetMsg(msg string) *RespData {
+	r.Msg = msg
+	return r
+}
+
+func SuccessResp(data interface{}) *RespData {
+	return &RespData{
 		Code: 0,
 		Msg:  "请求成功",
 		Data: data,
 	}
 }
 
-func ErrorResp(msg string) RespData {
-	return RespData{
+func ErrorResp(msg string) *RespData {
+	return &RespData{
 		Code: -1,
 		Msg:  msg,
 		Data: nil,
 	}
 }
 
-func NewErrorResp(error error) RespData {
-	return RespData{
+func NewErrorResp(error error) *RespData {
+	return &RespData{
 		Code: -1,
 		Msg:  error.Error(),
 		Data: nil,
 	}
 }
+
+func NewResp(code int, msg string, data interface{}) *RespData {
+	return &RespData{
+		Code: code,
+		Msg:  msg,
+		Data: data,
+	}
+}
+
+// 未登录
+var UnAuthResp = ErrorResp("未登录").SetCode(401)

+ 17 - 9
server/routers/router.go

@@ -10,23 +10,31 @@ import (
 	config2 "nginx-ui/server/config"
 	"nginx-ui/server/controllers"
 	"nginx-ui/server/middleware"
+	"nginx-ui/server/models"
 	"strings"
 )
 
+var NginxR = "/nginx"
+var NginxGetR = "/nginx/:id"
+var NginxRefreshR = "/nginx/:id/http/refresh"
+var NginxStartR = "/nginx/:id/start"
+var NginxStopR = "/nginx/:id/stop"
+var NginxStatusR = "/nginx/:id/status"
+
 func init() {
 	config := config2.Config
 
 	userController := controllers.NewUserController()
 
 	ns := beego.NewNamespace(config.BaseApi,
-		beego.NSRouter("/nginx", &controllers.NginxController{}),
-		beego.NSRouter("/nginx/:id", &controllers.NginxController{}, "post:Update"),
-		beego.NSRouter("/nginx/:id", &controllers.NginxController{}, "get:GetNginx"),
-		beego.NSRouter("/nginx/:id", &controllers.NginxController{}, "delete:DelNginx"),
-		beego.NSRouter("/nginx/:id/http/refresh", &controllers.NginxController{}, "post:RefreshHttp"),
-		beego.NSRouter("/nginx/:id/start", &controllers.NginxController{}, "post:StartNginx"),
-		beego.NSRouter("/nginx/:id/stop", &controllers.NginxController{}, "post:StopNginx"),
-		beego.NSRouter("/nginx/:id/status", &controllers.NginxController{}, "post:StatusNginx"),
+		beego.NSRouter(NginxR, &controllers.NginxController{}),
+		beego.NSRouter(NginxGetR, &controllers.NginxController{}, "post:Update"),
+		beego.NSRouter(NginxGetR, &controllers.NginxController{}, "get:GetNginx"),
+		beego.NSRouter(NginxGetR, &controllers.NginxController{}, "delete:DelNginx"),
+		beego.NSRouter(NginxRefreshR, &controllers.NginxController{}, "post:RefreshHttp"),
+		beego.NSRouter(NginxStartR, &controllers.NginxController{}, "post:StartNginx"),
+		beego.NSRouter(NginxStopR, &controllers.NginxController{}, "post:StopNginx"),
+		beego.NSRouter(NginxStatusR, &controllers.NginxController{}, "post:StatusNginx"),
 		// certs
 		beego.NSRouter("/nginx/:id/certs", &controllers.CertController{}),
 		beego.NSRouter("/nginx/:id/certs/sync", &controllers.CertController{}, "post:Sync"),
@@ -61,7 +69,7 @@ func init() {
 		if strings.Contains(accept, "json") {
 			writer.Header().Set("content-type", "application/json")
 			writer.WriteHeader(200)
-			resp := controllers.RespData{
+			resp := models.RespData{
 				Code: -2,
 				Msg:  "server error",
 			}

+ 298 - 0
server/service/nginx.go

@@ -0,0 +1,298 @@
+package service
+
+import (
+	"encoding/json"
+	"errors"
+	"github.com/astaxie/beego/logs"
+	"github.com/astaxie/beego/orm"
+	"nginx-ui/server/models"
+	ngx "nginx-ui/server/nginx"
+	"strconv"
+)
+
+type NginxService struct {
+}
+
+const ReplacePassword = "******"
+
+// CheckNginxPermission 从path中获取nginx的参数
+func (c *NginxService) CheckNginxPermission(user *models.User, nginxId string) (*models.Nginx, error) {
+	id, err := strconv.Atoi(nginxId)
+	if err != nil {
+		logs.Warn("strconv.Atoi(idStr) fail", nginxId)
+		return nil, errors.New("请传递正确的参数!")
+	}
+	return c.CheckNginxPermissionById(user, id)
+}
+
+// CheckNginxPermissionById 验证权限,如果无权操作该nginx,返回nil,否则返回
+func (c *NginxService) CheckNginxPermissionById(current *models.User, nginxId int) (*models.Nginx, error) {
+	if nginxId < 1 {
+		return nil, errors.New("nginx ID must gt 0!")
+	}
+	nginx := models.Nginx{Id: nginxId}
+	o := orm.NewOrm()
+	err := o.Read(&nginx)
+	if err != nil {
+		return nil, err
+	}
+	if !current.IsAdmin() && current.Account != nginx.Uid {
+		return nil, errors.New("您无权操作该实例")
+	}
+	return &nginx, nil
+}
+
+// Get getAll,
+// 管理员获取全部,非管理员或者自己名下的
+func (c *NginxService) ListNginx(current *models.User) *models.RespData {
+
+	if current == nil {
+		return models.UnAuthResp
+	}
+	o := orm.NewOrm()
+	qs := o.QueryTable("nginx")
+	if !current.IsAdmin() {
+		qs = qs.Filter("Uid", current.Account)
+	}
+	var list []*models.Nginx
+	_, err := qs.All(&list)
+	for i := range list {
+		item := list[i]
+		if item.Password != "" {
+			item.Password = ReplacePassword
+		}
+	}
+	if err != nil {
+		return models.NewErrorResp(err)
+	} else {
+		return models.SuccessResp(list)
+	}
+}
+
+// Post add nginx instance
+func (c *NginxService) Add(current *models.User, req []byte) *models.RespData {
+	if current == nil {
+		return models.UnAuthResp
+	}
+	var nginx models.Nginx
+	err := json.Unmarshal(req, &nginx)
+	if err != nil {
+		logs.Error(err, string(req))
+		return models.NewErrorResp(err)
+	}
+	nginx.Check()
+	o := orm.NewOrm()
+
+	nginx.Uid = current.Account
+	nginx.NginxPath = "/usr/sbin/nginx"
+	nginx.NginxDir = "/etc/nginx"
+	if nginx.IsLocal {
+		nginx.IsServer = true
+	}
+	nginx.DataDir = "/app/data"
+	_, err = o.Insert(&nginx)
+
+	if err != nil {
+		return models.NewErrorResp(err)
+	}
+	logs.Info("post", nginx)
+
+	instance := ngx.GetInstance(&nginx)
+	err = instance.Connect()
+	if err != nil {
+		return models.SuccessResp(nginx).SetCode(1).SetMsg(err.Error())
+	}
+	out, err := instance.GetVersion()
+	if err != nil {
+		return models.SuccessResp(nginx).SetCode(1).SetMsg(err.Error())
+	}
+	nginx.VersionInfo = out
+	_, _ = o.Update(&nginx, "VersionInfo")
+	return models.SuccessResp(nginx)
+}
+
+// Update modify nginx instance
+// post /nginx/:id
+func (c *NginxService) Update(nginxId string, current *models.User, req []byte) *models.RespData {
+	if current == nil {
+		return models.UnAuthResp
+	}
+
+	var nginx models.Nginx
+	err := json.Unmarshal(req, &nginx)
+	if err != nil {
+		logs.Error(err, string(req))
+		return models.NewErrorResp(err)
+	}
+
+	exist, err := c.CheckNginxPermission(current, nginxId)
+	if err != nil {
+		return models.NewErrorResp(err)
+	}
+
+	nginx.Id = exist.Id
+	nginx.Uid = exist.Uid
+	nginx.Check()
+	o := orm.NewOrm()
+
+	if nginx.Password == ReplacePassword {
+		nginx.Password = exist.Password
+	}
+	nginx.HttpConf = exist.HttpConf
+	_, err = o.Update(&nginx)
+
+	if err != nil {
+		return models.NewErrorResp(err)
+	}
+	logs.Info("post", nginx)
+
+	instance := ngx.GetInstance(&nginx)
+	err = instance.Connect()
+	if err != nil {
+		return models.NewResp(1, err.Error(), nginx)
+	}
+	out, err := instance.GetVersion()
+	if err != nil {
+		return models.NewResp(1, err.Error(), nginx)
+	}
+	nginx.VersionInfo = out
+	_, _ = o.Update(&nginx, "VersionInfo")
+	return models.SuccessResp(nginx)
+}
+
+// StartNginx startNginx
+// post /nginx/:id/start
+func (c *NginxService) StartNginx(nginxId string, user *models.User) *models.RespData {
+	if user == nil {
+		return models.UnAuthResp
+	}
+
+	nginx, err := c.CheckNginxPermission(user, nginxId)
+	if err != nil {
+		return models.NewErrorResp(err)
+	}
+
+	instance := ngx.GetInstance(nginx)
+	err = instance.Start()
+	isRun, msg := instance.Status()
+	return models.SuccessResp(isRun).SetMsg(msg)
+}
+
+// StopNginx add nginx instance
+// post /nginx/:id/stop
+func (c *NginxService) StopNginx(nginxId string, user *models.User) *models.RespData {
+	if user == nil {
+		return models.UnAuthResp
+	}
+
+	nginx, err := c.CheckNginxPermission(user, nginxId)
+	if err != nil {
+		return models.NewErrorResp(err)
+	}
+	instance := ngx.GetInstance(nginx)
+	err = instance.Stop()
+	isRun, msg := instance.Status()
+	return models.SuccessResp(isRun).SetMsg(msg)
+}
+
+// RefreshHttp nginx detail data
+// post /nginx/:id/http/refresh
+func (c *NginxService) RefreshHttp(nginxId string, user *models.User, req []byte) *models.RespData {
+	if user == nil {
+		return models.UnAuthResp
+	}
+
+	exist, err := c.CheckNginxPermission(user, nginxId)
+	if err != nil {
+		return models.NewErrorResp(err)
+	}
+
+	var nginx models.Nginx
+	err = json.Unmarshal(req, &nginx)
+	if err != nil {
+		logs.Error(err, string(req))
+		return models.NewErrorResp(err)
+	}
+
+	logs.Info("id", nginx)
+
+	o := orm.NewOrm()
+	if nginx.HttpConf != "" {
+		_, err = o.Update(&nginx, "HttpConf", "HttpData")
+		if err != nil {
+			return models.NewErrorResp(err)
+		}
+		exist.HttpConf = nginx.HttpConf
+		exist.HttpData = nginx.HttpData
+	}
+
+	ins := ngx.GetInstance(exist)
+	err = ins.RefreshHttp(*exist)
+	if err != nil {
+		return models.NewErrorResp(err)
+	}
+	return models.SuccessResp(nil)
+}
+
+// GetNginx nginx detail data
+// get /nginx/:id
+func (c *NginxService) GetNginx(nginxId string, user *models.User) *models.RespData {
+	if user == nil {
+		return models.UnAuthResp
+	}
+
+	nginx, err := c.CheckNginxPermission(user, nginxId)
+	if err != nil {
+		return models.NewErrorResp(err)
+	}
+	if nginx.Password != "" {
+		nginx.Password = ReplacePassword
+	}
+	var resp = map[string]interface{}{}
+	resp["nginx"] = nginx
+	o := orm.NewOrm()
+
+	var servers []models.ServerHost
+	_, err = o.QueryTable((*models.ServerHost)(nil)).Filter("NginxId", nginx.Id).All(&servers)
+	if err != nil {
+		return models.NewErrorResp(err)
+	}
+	resp["servers"] = servers
+	return models.SuccessResp(resp)
+}
+
+// DelNginx delete a instance
+// delete /nginx/:id
+func (c *NginxService) DelNginx(nginxId string, user *models.User) *models.RespData {
+	if user == nil {
+		return models.UnAuthResp
+	}
+
+	nginx, err := c.CheckNginxPermission(user, nginxId)
+	if err != nil {
+		return models.NewErrorResp(err)
+	}
+	o := orm.NewOrm()
+	count, err := o.Delete(nginx, "Id")
+	if err != nil {
+		return models.NewErrorResp(err)
+	} else {
+		return models.SuccessResp(count)
+	}
+}
+
+// StatusNginx add nginx instance
+// post /nginx/:id/status
+func (c *NginxService) StatusNginx(nginxId string, user *models.User) *models.RespData {
+	if user == nil {
+		return models.UnAuthResp
+	}
+
+	nginx, err := c.CheckNginxPermission(user, nginxId)
+	if err != nil {
+		return models.NewErrorResp(err)
+	}
+	instance := ngx.GetInstance(nginx)
+	isRun, msg := instance.Status()
+	return models.SuccessResp(isRun).SetMsg(msg)
+}

+ 20 - 7
server/service/user.go

@@ -1,7 +1,8 @@
 package service
 
 import (
-	"errors"
+	"encoding/json"
+	"github.com/astaxie/beego/logs"
 	"github.com/astaxie/beego/orm"
 	"nginx-ui/server/models"
 	"nginx-ui/server/utils"
@@ -14,10 +15,10 @@ func NewUserService() *UserService {
 	return &UserService{}
 }
 
-func (u *UserService) Login(user models.User) models.RespData {
+func (u *UserService) Login(user *models.User) *models.RespData {
 	cipherPassword := user.Password
 	o := orm.NewOrm()
-	err := o.Read(&user, "Account")
+	err := o.Read(user, "Account")
 	if err != nil {
 		return models.NewErrorResp(err)
 	}
@@ -29,16 +30,28 @@ func (u *UserService) Login(user models.User) models.RespData {
 	return models.SuccessResp(user)
 }
 
-func (u *UserService) SignUp(user models.User) error {
+func (u *UserService) SignUp(req []byte) *models.RespData {
+
+	var user models.User
+	err := json.Unmarshal(req, &user)
+	if err != nil {
+		logs.Error(err, req)
+		return models.NewErrorResp(err)
+	}
 
 	if len(user.Account) == 0 || len(user.Password) == 0 {
-		return errors.New("账号或者密码不能为空!")
+		return models.ErrorResp("账号或者密码不能为空!")
 	}
 	if len(user.Nickname) == 0 {
 		user.Nickname = user.Account
 	}
 	user.Password = utils.GetSHA256HashCode(user.Password)
 	o := orm.NewOrm()
-	_, err := o.Insert(&user)
-	return err
+	_, err = o.Insert(&user)
+
+	if err != nil {
+		return models.NewErrorResp(err)
+	}
+
+	return models.SuccessResp(user).SetMsg("注册成功!")
 }

+ 10 - 2
wails.json

@@ -4,11 +4,19 @@
   "outputfilename": "nginx-ui",
   "frontend:dir": "frontend",
   "frontend:install": "yarn",
-  "frontend:build": "npm run build",
+  "frontend:build": "npm run desktop",
   "frontend:dev:watcher": "npm run dev",
   "frontend:dev:serverUrl": "auto",
   "author": {
     "name": "tuon",
     "email": "976056042@qq.com"
-  }
+  },
+  "info": {
+    "companyName": "tuonian",
+    "productName": "nginx-ui",
+    "productVersion": "v1.0.0",
+    "copyright": "tonyandmoney.cn",
+    "comments": ""
+  },
+  "nsisType": "single"
 }

Some files were not shown because too many files changed in this diff