diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index f869ba3..bf74345 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -18,7 +18,23 @@ jobs: with: go-version: 1.17 - - name: Build + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: "18.x" + + - run: yarn + name: WebUI - Install Dependencies + working-directory: webui + + - run: yarn build + name: WebUI - Build + working-directory: webui + + - name: Build with WebUI + run: go build -tags withUI -v ./... + + - name: Build without WebUI run: go build -v ./... - name: Test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0001af5..3a22fff 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,10 +20,21 @@ jobs: goos: windows steps: - uses: actions/checkout@v2 - - uses: wangyoucao577/go-release-action@v1.25 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: "18.x" + - run: yarn + name: WebUI - Install Dependencies + working-directory: webui + - run: yarn build + name: WebUI - Build + working-directory: webui + - uses: wangyoucao577/go-release-action@v1.30 with: github_token: ${{ secrets.GITHUB_TOKEN }} goos: ${{ matrix.goos }} goarch: ${{ matrix.goarch }} goversion: "https://go.dev/dl/go1.17.7.linux-amd64.tar.gz" - extra_files: LICENSE README.md \ No newline at end of file + extra_files: LICENSE README.md + build_flags: '-tags withUI' \ No newline at end of file diff --git a/README.md b/README.md index 4f9c7f5..fbca482 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,18 @@ statistical work. [![Crowdin](https://badges.crowdin.net/matrix-veles/localized.svg)](https://crowdin.com/project/matrix-veles) If you have time and language skills, consider [helping to translate the docs](https://crwd.in/matrix-veles)! + +## Building + +### Building without WebUI + +Simply run `go build` in the project directory. + +### Building with WebUI + +Make sure you have NodeJS and Yarn installed. + +Then run the following commands: + +1. `go generate ./...` - This will build the webui react project. +2. `go build -tags withUI` - This will build the binary with included UI. diff --git a/internal/web/web.go b/internal/web/web.go index 47d1a81..9fee927 100644 --- a/internal/web/web.go +++ b/internal/web/web.go @@ -2,12 +2,14 @@ package web import ( "github.com/Unkn0wnCat/matrix-veles/internal/web/api" + "github.com/Unkn0wnCat/matrix-veles/webui" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/spf13/viper" "log" "net/http" + "strings" "time" ) @@ -23,11 +25,26 @@ func StartServer() { r.Handle("/metrics", promhttp.Handler()) - r.HandleFunc("/", HomeHandler) + //r.HandleFunc("/", HomeHandler) //r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static")))) r.Mount("/api", api.SetupAPI()) + r.NotFound(func(w http.ResponseWriter, r *http.Request) { + if strings.HasPrefix(r.URL.Path, "/api") { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(404) + w.Write([]byte("{\"error_code\": 404, \"error\": \"not_found\"}")) + return + } + return + }) + + ui, err := webui.ServeUI() + if err == nil { + r.Mount("/", ui) + } + srv := &http.Server{ Handler: r, Addr: viper.GetString("bot.web.listen"), diff --git a/webui/webui.go b/webui/webui.go new file mode 100644 index 0000000..df6fefc --- /dev/null +++ b/webui/webui.go @@ -0,0 +1,58 @@ +//go:build withUI +// +build withUI + +package webui + +//go:generate yarn +//go:generate yarn build + +import ( + "embed" + "io/fs" + "log" + "net/http" + "path" + "strings" +) + +//go:embed build/* +var content embed.FS + +func ServeUI() (http.Handler, error) { + fSys, err := fs.Sub(content, "build") + if err != nil { + return nil, err + } + + staticServer := http.FileServer(http.FS(fSys)) + + serveIndex, err := ServeIndex() + if err != nil { + return nil, err + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, err := fSys.Open(strings.TrimPrefix(path.Clean(r.URL.Path), "/")) + if err != nil { + log.Println(err) + serveIndex.ServeHTTP(w, r) + return + } + log.Println("serving static") + staticServer.ServeHTTP(w, r) + }), nil +} + +func ServeIndex() (http.HandlerFunc, error) { + indexFile, err := content.ReadFile("build/index.html") + if err != nil { + return nil, err + } + + return func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html") + + w.WriteHeader(200) + w.Write(indexFile) + }, nil +} diff --git a/webui/webuiNotIncluded.go b/webui/webuiNotIncluded.go new file mode 100644 index 0000000..77664a2 --- /dev/null +++ b/webui/webuiNotIncluded.go @@ -0,0 +1,20 @@ +//go:build !withUI +// +build !withUI + +package webui + +//go:generate yarn +//go:generate yarn build + +import ( + "net/http" +) + +func ServeUI() (http.Handler, error) { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(404) + w.Write([]byte("{\"error_code\": 404, \"error\": \"not_found\", \"note\": \"WebUI not included in build - visit https://veles.1in1.net/docs/tutorial-basics/install\"}")) + return + }), nil +}