mirror of
https://github.com/taigrr/wails.git
synced 2026-04-04 14:12:40 -07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71bfd29376 |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -17,3 +17,12 @@ cmd/wails/wails
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
tmp
|
tmp
|
||||||
node_modules/
|
node_modules/
|
||||||
|
package.json.md5
|
||||||
|
v2/test/**/frontend/dist
|
||||||
|
v2/test/**/build/
|
||||||
|
v2/test/frameless/icon.png
|
||||||
|
v2/test/hidden/icon.png
|
||||||
|
v2/internal/ffenestri/runtime.c
|
||||||
|
v2/internal/runtime/assets/desktop.js
|
||||||
|
v2/test/kitchensink/frontend/public/bundle.*
|
||||||
|
v2/pkg/parser/testproject/frontend/wails
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -22,7 +22,7 @@ require (
|
|||||||
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba
|
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba
|
||||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8
|
golang.org/x/image v0.0.0-20200430140353-33d19683fad8
|
||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
|
||||||
golang.org/x/text v0.3.0
|
golang.org/x/text v0.3.0
|
||||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4
|
gopkg.in/AlecAivazis/survey.v1 v1.8.4
|
||||||
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
|
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -81,6 +81,8 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
|
||||||
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc=
|
gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc=
|
||||||
|
|||||||
13
v2/.vscode/settings.json
vendored
Normal file
13
v2/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"ios": "c",
|
||||||
|
"typeinfo": "c",
|
||||||
|
"sstream": "c",
|
||||||
|
"__functional_03": "c",
|
||||||
|
"functional": "c",
|
||||||
|
"__locale": "c",
|
||||||
|
"locale": "c",
|
||||||
|
"chrono": "c",
|
||||||
|
"system_error": "c"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,19 +2,19 @@ package build
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"io"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
"github.com/leaanthony/clir"
|
||||||
"github.com/leaanthony/slicer"
|
"github.com/leaanthony/slicer"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddBuildSubcommand adds the `build` command for the Wails application
|
// AddBuildSubcommand adds the `build` command for the Wails application
|
||||||
func AddBuildSubcommand(app *clir.Cli) {
|
func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||||
|
|
||||||
outputType := "desktop"
|
outputType := "desktop"
|
||||||
|
|
||||||
@@ -56,11 +56,8 @@ func AddBuildSubcommand(app *clir.Cli) {
|
|||||||
command.Action(func() error {
|
command.Action(func() error {
|
||||||
|
|
||||||
// Create logger
|
// Create logger
|
||||||
logger := logger.New()
|
logger := clilogger.New(w)
|
||||||
|
logger.Mute(quiet)
|
||||||
if !quiet {
|
|
||||||
logger.AddOutput(os.Stdout)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate output type
|
// Validate output type
|
||||||
if !validTargetTypes.Contains(outputType) {
|
if !validTargetTypes.Contains(outputType) {
|
||||||
@@ -72,8 +69,8 @@ func AddBuildSubcommand(app *clir.Cli) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
task := fmt.Sprintf("Building %s Application", strings.Title(outputType))
|
task := fmt.Sprintf("Building %s Application", strings.Title(outputType))
|
||||||
logger.Writeln(task)
|
logger.Println(task)
|
||||||
logger.Writeln(strings.Repeat("-", len(task)))
|
logger.Println(strings.Repeat("-", len(task)))
|
||||||
|
|
||||||
// Setup mode
|
// Setup mode
|
||||||
mode := build.Debug
|
mode := build.Debug
|
||||||
@@ -108,9 +105,9 @@ func doBuild(buildOptions *build.Options) error {
|
|||||||
}
|
}
|
||||||
// Output stats
|
// Output stats
|
||||||
elapsed := time.Since(start)
|
elapsed := time.Since(start)
|
||||||
buildOptions.Logger.Writeln("")
|
buildOptions.Logger.Println("")
|
||||||
buildOptions.Logger.Writeln(fmt.Sprintf("Built '%s' in %s.", outputFilename, elapsed.Round(time.Millisecond).String()))
|
buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.", outputFilename, elapsed.Round(time.Millisecond).String()))
|
||||||
buildOptions.Logger.Writeln("")
|
buildOptions.Logger.Println("")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package dev
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -13,13 +14,13 @@ import (
|
|||||||
"github.com/leaanthony/clir"
|
"github.com/leaanthony/clir"
|
||||||
"github.com/leaanthony/slicer"
|
"github.com/leaanthony/slicer"
|
||||||
"github.com/wailsapp/wails/v2/internal/fs"
|
"github.com/wailsapp/wails/v2/internal/fs"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/process"
|
"github.com/wailsapp/wails/v2/internal/process"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddSubcommand adds the `dev` command for the Wails application
|
// AddSubcommand adds the `dev` command for the Wails application
|
||||||
func AddSubcommand(app *clir.Cli) error {
|
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||||
|
|
||||||
command := app.NewSubCommand("dev", "Development mode")
|
command := app.NewSubCommand("dev", "Development mode")
|
||||||
|
|
||||||
@@ -51,8 +52,7 @@ func AddSubcommand(app *clir.Cli) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create logger
|
// Create logger
|
||||||
logger := logger.New()
|
logger := clilogger.New(w)
|
||||||
logger.AddOutput(os.Stdout)
|
|
||||||
app.PrintBanner()
|
app.PrintBanner()
|
||||||
|
|
||||||
// TODO: Check you are in a project directory
|
// TODO: Check you are in a project directory
|
||||||
@@ -74,11 +74,11 @@ func AddSubcommand(app *clir.Cli) error {
|
|||||||
debounceQuit := make(chan bool, 1)
|
debounceQuit := make(chan bool, 1)
|
||||||
|
|
||||||
// Do initial build
|
// Do initial build
|
||||||
logger.Info("Building application for development...")
|
logger.Println("Building application for development...")
|
||||||
debugBinaryProcess = restartApp(logger, outputType, ldflags, compilerCommand, buildFrontend, debugBinaryProcess)
|
debugBinaryProcess = restartApp(logger, outputType, ldflags, compilerCommand, buildFrontend, debugBinaryProcess)
|
||||||
|
|
||||||
go debounce(100*time.Millisecond, watcher.Events, debounceQuit, func(event fsnotify.Event) {
|
go debounce(100*time.Millisecond, watcher.Events, debounceQuit, func(event fsnotify.Event) {
|
||||||
// logger.Info("event: %+v", event)
|
// logger.Println("event: %+v", event)
|
||||||
|
|
||||||
// Check for new directories
|
// Check for new directories
|
||||||
if event.Op&fsnotify.Create == fsnotify.Create {
|
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||||
@@ -86,7 +86,7 @@ func AddSubcommand(app *clir.Cli) error {
|
|||||||
if fs.DirExists(event.Name) {
|
if fs.DirExists(event.Name) {
|
||||||
if !strings.Contains(event.Name, "node_modules") {
|
if !strings.Contains(event.Name, "node_modules") {
|
||||||
watcher.Add(event.Name)
|
watcher.Add(event.Name)
|
||||||
logger.Info("Watching directory: %s", event.Name)
|
logger.Println("Watching directory: %s", event.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -95,7 +95,7 @@ func AddSubcommand(app *clir.Cli) error {
|
|||||||
// Check for file writes
|
// Check for file writes
|
||||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||||
|
|
||||||
// logger.Info("modified file: %s", event.Name)
|
// logger.Println("modified file: %s", event.Name)
|
||||||
var rebuild bool = false
|
var rebuild bool = false
|
||||||
|
|
||||||
// Iterate all file patterns
|
// Iterate all file patterns
|
||||||
@@ -112,14 +112,14 @@ func AddSubcommand(app *clir.Cli) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !rebuild {
|
if !rebuild {
|
||||||
logger.Info("Filename change: %s did not match extension list %s", event.Name, extensions)
|
logger.Println("Filename change: %s did not match extension list %s", event.Name, extensions)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if buildFrontend {
|
if buildFrontend {
|
||||||
logger.Info("Full rebuild triggered: %s updated", event.Name)
|
logger.Println("Full rebuild triggered: %s updated", event.Name)
|
||||||
} else {
|
} else {
|
||||||
logger.Info("Partial build triggered: %s updated", event.Name)
|
logger.Println("Partial build triggered: %s updated", event.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do a rebuild
|
// Do a rebuild
|
||||||
@@ -152,7 +152,7 @@ func AddSubcommand(app *clir.Cli) error {
|
|||||||
if strings.Contains(dir, "node_modules") {
|
if strings.Contains(dir, "node_modules") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Info("Watching directory: %s", dir)
|
logger.Println("Watching directory: %s", dir)
|
||||||
err = watcher.Add(dir)
|
err = watcher.Add(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(err.Error())
|
logger.Fatal(err.Error())
|
||||||
@@ -176,7 +176,7 @@ func AddSubcommand(app *clir.Cli) error {
|
|||||||
debugBinaryProcess.Kill()
|
debugBinaryProcess.Kill()
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("Development mode exited")
|
logger.Println("Development mode exited")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@@ -203,15 +203,15 @@ exit:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func restartApp(logger *logger.Logger, outputType string, ldflags string, compilerCommand string, buildFrontend bool, debugBinaryProcess *process.Process) *process.Process {
|
func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, buildFrontend bool, debugBinaryProcess *process.Process) *process.Process {
|
||||||
|
|
||||||
appBinary, err := buildApp(logger, outputType, ldflags, compilerCommand, buildFrontend)
|
appBinary, err := buildApp(logger, outputType, ldflags, compilerCommand, buildFrontend)
|
||||||
println()
|
println()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Build Failed: %s", err.Error())
|
logger.Println("[ERROR] Build Failed: %s", err.Error())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
logger.Info("Build new binary: %s", appBinary)
|
logger.Println("Build new binary: %s", appBinary)
|
||||||
|
|
||||||
// Kill existing binary if need be
|
// Kill existing binary if need be
|
||||||
if debugBinaryProcess != nil {
|
if debugBinaryProcess != nil {
|
||||||
@@ -238,7 +238,7 @@ func restartApp(logger *logger.Logger, outputType string, ldflags string, compil
|
|||||||
return newProcess
|
return newProcess
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildApp(logger *logger.Logger, outputType string, ldflags string, compilerCommand string, buildFrontend bool) (string, error) {
|
func buildApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, buildFrontend bool) (string, error) {
|
||||||
|
|
||||||
// Create random output file
|
// Create random output file
|
||||||
outputFile := fmt.Sprintf("debug-%d", time.Now().Unix())
|
outputFile := fmt.Sprintf("debug-%d", time.Now().Unix())
|
||||||
|
|||||||
@@ -2,37 +2,37 @@ package doctor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
"github.com/leaanthony/clir"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/system"
|
"github.com/wailsapp/wails/v2/internal/system"
|
||||||
"github.com/wailsapp/wails/v2/internal/system/packagemanager"
|
"github.com/wailsapp/wails/v2/internal/system/packagemanager"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddSubcommand adds the `doctor` command for the Wails application
|
// AddSubcommand adds the `doctor` command for the Wails application
|
||||||
func AddSubcommand(app *clir.Cli) error {
|
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||||
|
|
||||||
command := app.NewSubCommand("doctor", "Diagnose your environment")
|
command := app.NewSubCommand("doctor", "Diagnose your environment")
|
||||||
|
|
||||||
command.Action(func() error {
|
command.Action(func() error {
|
||||||
|
|
||||||
// Create logger
|
logger := clilogger.New(w)
|
||||||
logger := logger.New()
|
|
||||||
logger.AddOutput(os.Stdout)
|
|
||||||
|
|
||||||
app.PrintBanner()
|
app.PrintBanner()
|
||||||
print("Scanning system - please wait...")
|
logger.Print("Scanning system - please wait...")
|
||||||
|
|
||||||
// Get system info
|
// Get system info
|
||||||
info, err := system.GetInfo()
|
info, err := system.GetInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
println("Done.")
|
logger.Println("Done.")
|
||||||
|
|
||||||
// Start a new tabwriter
|
// Start a new tabwriter
|
||||||
w := new(tabwriter.Writer)
|
w := new(tabwriter.Writer)
|
||||||
@@ -112,22 +112,22 @@ func AddSubcommand(app *clir.Cli) error {
|
|||||||
fmt.Fprintf(w, "\n")
|
fmt.Fprintf(w, "\n")
|
||||||
fmt.Fprintf(w, "* - Optional Dependency\n")
|
fmt.Fprintf(w, "* - Optional Dependency\n")
|
||||||
w.Flush()
|
w.Flush()
|
||||||
println()
|
logger.Println("")
|
||||||
println("Diagnosis")
|
logger.Println("Diagnosis")
|
||||||
println("---------\n")
|
logger.Println("---------\n")
|
||||||
|
|
||||||
// Generate an appropriate diagnosis
|
// Generate an appropriate diagnosis
|
||||||
|
|
||||||
if len(dependenciesMissing) == 0 && dependenciesAvailableRequired == 0 {
|
if len(dependenciesMissing) == 0 && dependenciesAvailableRequired == 0 {
|
||||||
println("Your system is ready for Wails development!")
|
logger.Println("Your system is ready for Wails development!")
|
||||||
}
|
}
|
||||||
|
|
||||||
if dependenciesAvailableRequired != 0 {
|
if dependenciesAvailableRequired != 0 {
|
||||||
println("Install required packages using: " + info.Dependencies.InstallAllRequiredCommand())
|
log.Println("Install required packages using: " + info.Dependencies.InstallAllRequiredCommand())
|
||||||
}
|
}
|
||||||
|
|
||||||
if dependenciesAvailableOptional != 0 {
|
if dependenciesAvailableOptional != 0 {
|
||||||
println("Install optional packages using: " + info.Dependencies.InstallAllOptionalCommand())
|
log.Println("Install optional packages using: " + info.Dependencies.InstallAllOptionalCommand())
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(externalPackages) > 0 {
|
if len(externalPackages) > 0 {
|
||||||
@@ -135,18 +135,18 @@ func AddSubcommand(app *clir.Cli) error {
|
|||||||
if p.Optional {
|
if p.Optional {
|
||||||
print("[Optional] ")
|
print("[Optional] ")
|
||||||
}
|
}
|
||||||
println("Install " + p.Name + ": " + p.InstallCommand)
|
log.Println("Install " + p.Name + ": " + p.InstallCommand)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dependenciesMissing) != 0 {
|
if len(dependenciesMissing) != 0 {
|
||||||
// TODO: Check if apps are available locally and if so, adjust the diagnosis
|
// TODO: Check if apps are available locally and if so, adjust the diagnosis
|
||||||
println("Fatal:")
|
log.Println("Fatal:")
|
||||||
println("Required dependencies missing: " + strings.Join(dependenciesMissing, " "))
|
log.Println("Required dependencies missing: " + strings.Join(dependenciesMissing, " "))
|
||||||
println("Please read this article on how to resolve this: https://wails.app/guides/resolving-missing-packages")
|
log.Println("Please read this article on how to resolve this: https://wails.app/guides/resolving-missing-packages")
|
||||||
}
|
}
|
||||||
|
|
||||||
println()
|
log.Println("")
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
91
v2/cmd/wails/internal/commands/generate/generate.go
Normal file
91
v2/cmd/wails/internal/commands/generate/generate.go
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package generate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/leaanthony/clir"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddSubcommand adds the `dev` command for the Wails application
|
||||||
|
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||||
|
|
||||||
|
command := app.NewSubCommand("generate", "Code Generation Tools")
|
||||||
|
|
||||||
|
// Backend API
|
||||||
|
backendAPI := command.NewSubCommand("module", "Generates a JS module for the frontend to interface with the backend")
|
||||||
|
|
||||||
|
// Quiet Init
|
||||||
|
quiet := false
|
||||||
|
backendAPI.BoolFlag("q", "Supress output to console", &quiet)
|
||||||
|
|
||||||
|
backendAPI.Action(func() error {
|
||||||
|
|
||||||
|
// Create logger
|
||||||
|
logger := clilogger.New(w)
|
||||||
|
logger.Mute(quiet)
|
||||||
|
|
||||||
|
app.PrintBanner()
|
||||||
|
|
||||||
|
logger.Print("Generating Javascript module for Go code...")
|
||||||
|
|
||||||
|
// Start Time
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
p, err := parser.GenerateWailsFrontendPackage()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Println("done.")
|
||||||
|
logger.Println("")
|
||||||
|
|
||||||
|
elapsed := time.Since(start)
|
||||||
|
packages := p.Packages
|
||||||
|
|
||||||
|
// Print report
|
||||||
|
for _, pkg := range p.Packages {
|
||||||
|
if pkg.ShouldGenerate() {
|
||||||
|
logPackage(pkg, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Println("%d packages parsed in %s.", len(packages), elapsed)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func logPackage(pkg *parser.Package, logger *clilogger.CLILogger) {
|
||||||
|
|
||||||
|
logger.Println("Processed Go package '" + pkg.Gopackage.Name + "' as '" + pkg.Name + "'")
|
||||||
|
for _, strct := range pkg.Structs() {
|
||||||
|
logger.Println("")
|
||||||
|
logger.Println(" Processed struct '" + strct.Name + "'")
|
||||||
|
if strct.IsBound {
|
||||||
|
for _, method := range strct.Methods {
|
||||||
|
logger.Println(" Bound method '" + method.Name + "'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strct.IsUsedAsData {
|
||||||
|
for _, field := range strct.Fields {
|
||||||
|
if !field.Ignored {
|
||||||
|
logger.Print(" Processed ")
|
||||||
|
if field.IsOptional {
|
||||||
|
logger.Print("optional ")
|
||||||
|
}
|
||||||
|
logger.Println("field '" + field.Name + "' as '" + field.JSName() + "'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Println("")
|
||||||
|
|
||||||
|
// logger.Println(" Original Go Package Path:", pkg.Gopackage.PkgPath)
|
||||||
|
// logger.Println(" Original Go Package Path:", pkg.Gopackage.PkgPath)
|
||||||
|
}
|
||||||
@@ -2,17 +2,17 @@ package initialise
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
"github.com/leaanthony/clir"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/templates"
|
"github.com/wailsapp/wails/v2/internal/templates"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddSubcommand adds the `init` command for the Wails application
|
// AddSubcommand adds the `init` command for the Wails application
|
||||||
func AddSubcommand(app *clir.Cli) error {
|
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||||
|
|
||||||
// Load the template shortnames
|
// Load the template shortnames
|
||||||
validShortNames, err := templates.TemplateShortNames()
|
validShortNames, err := templates.TemplateShortNames()
|
||||||
@@ -32,13 +32,17 @@ func AddSubcommand(app *clir.Cli) error {
|
|||||||
command.StringFlag("n", "Name of project", &projectName)
|
command.StringFlag("n", "Name of project", &projectName)
|
||||||
|
|
||||||
// Setup project directory
|
// Setup project directory
|
||||||
projectDirectory := "."
|
projectDirectory := ""
|
||||||
command.StringFlag("d", "Project directory", &projectDirectory)
|
command.StringFlag("d", "Project directory", &projectDirectory)
|
||||||
|
|
||||||
// Quiet Init
|
// Quiet Init
|
||||||
quiet := false
|
quiet := false
|
||||||
command.BoolFlag("q", "Supress output to console", &quiet)
|
command.BoolFlag("q", "Supress output to console", &quiet)
|
||||||
|
|
||||||
|
// VSCode project files
|
||||||
|
vscode := false
|
||||||
|
command.BoolFlag("vscode", "Generate VSCode project files", &vscode)
|
||||||
|
|
||||||
// List templates
|
// List templates
|
||||||
list := false
|
list := false
|
||||||
command.BoolFlag("l", "List templates", &list)
|
command.BoolFlag("l", "List templates", &list)
|
||||||
@@ -46,32 +50,29 @@ func AddSubcommand(app *clir.Cli) error {
|
|||||||
command.Action(func() error {
|
command.Action(func() error {
|
||||||
|
|
||||||
// Create logger
|
// Create logger
|
||||||
logger := logger.New()
|
logger := clilogger.New(w)
|
||||||
|
logger.Mute(quiet)
|
||||||
if !quiet {
|
|
||||||
logger.AddOutput(os.Stdout)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Are we listing templates?
|
// Are we listing templates?
|
||||||
if list {
|
if list {
|
||||||
app.PrintBanner()
|
app.PrintBanner()
|
||||||
err := templates.OutputList(logger)
|
err := templates.OutputList(logger)
|
||||||
logger.Writeln("")
|
logger.Println("")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate output type
|
// Validate output type
|
||||||
if !validShortNames.Contains(templateName) {
|
if !validShortNames.Contains(templateName) {
|
||||||
logger.Write(fmt.Sprintf("ERROR: Template '%s' is not valid", templateName))
|
logger.Print(fmt.Sprintf("[ERROR] Template '%s' is not valid", templateName))
|
||||||
logger.Writeln("")
|
logger.Println("")
|
||||||
command.PrintHelp()
|
command.PrintHelp()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate name
|
// Validate name
|
||||||
if len(projectName) == 0 {
|
if len(projectName) == 0 {
|
||||||
logger.Writeln("ERROR: Project name required")
|
logger.Println("ERROR: Project name required")
|
||||||
logger.Writeln("")
|
logger.Println("")
|
||||||
command.PrintHelp()
|
command.PrintHelp()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -81,15 +82,16 @@ func AddSubcommand(app *clir.Cli) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
task := fmt.Sprintf("Initialising Project %s", strings.Title(projectName))
|
task := fmt.Sprintf("Initialising Project %s", strings.Title(projectName))
|
||||||
logger.Writeln(task)
|
logger.Println(task)
|
||||||
logger.Writeln(strings.Repeat("-", len(task)))
|
logger.Println(strings.Repeat("-", len(task)))
|
||||||
|
|
||||||
// Create Template Options
|
// Create Template Options
|
||||||
options := &templates.Options{
|
options := &templates.Options{
|
||||||
ProjectName: projectName,
|
ProjectName: projectName,
|
||||||
TargetDir: projectDirectory,
|
TargetDir: projectDirectory,
|
||||||
TemplateName: templateName,
|
TemplateName: templateName,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
|
GenerateVSCode: vscode,
|
||||||
}
|
}
|
||||||
|
|
||||||
return initProject(options)
|
return initProject(options)
|
||||||
@@ -112,9 +114,17 @@ func initProject(options *templates.Options) error {
|
|||||||
|
|
||||||
// Output stats
|
// Output stats
|
||||||
elapsed := time.Since(start)
|
elapsed := time.Since(start)
|
||||||
options.Logger.Writeln("")
|
options.Logger.Println("")
|
||||||
options.Logger.Writeln(fmt.Sprintf("Initialised project '%s' in %s.", options.ProjectName, elapsed.Round(time.Millisecond).String()))
|
options.Logger.Println("Project Name: " + options.ProjectName)
|
||||||
options.Logger.Writeln("")
|
options.Logger.Println("Project Directory: " + options.TargetDir)
|
||||||
|
options.Logger.Println("Project Template: " + options.TemplateName)
|
||||||
|
options.Logger.Println("")
|
||||||
|
if options.GenerateVSCode {
|
||||||
|
options.Logger.Println("VSCode config files generated.")
|
||||||
|
}
|
||||||
|
options.Logger.Println("")
|
||||||
|
options.Logger.Println(fmt.Sprintf("Initialised project '%s' in %s.", options.ProjectName, elapsed.Round(time.Millisecond).String()))
|
||||||
|
options.Logger.Println("")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/build"
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/build"
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/dev"
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/dev"
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/doctor"
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/doctor"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate"
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/initialise"
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/initialise"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,17 +23,22 @@ func main() {
|
|||||||
|
|
||||||
app := clir.NewCli("Wails", "Go/HTML Application Framework", version)
|
app := clir.NewCli("Wails", "Go/HTML Application Framework", version)
|
||||||
|
|
||||||
build.AddBuildSubcommand(app)
|
build.AddBuildSubcommand(app, os.Stdout)
|
||||||
err = initialise.AddSubcommand(app)
|
err = initialise.AddSubcommand(app, os.Stdout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatal(err.Error())
|
fatal(err.Error())
|
||||||
}
|
}
|
||||||
err = doctor.AddSubcommand(app)
|
err = doctor.AddSubcommand(app, os.Stdout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatal(err.Error())
|
fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
err = dev.AddSubcommand(app)
|
err = dev.AddSubcommand(app, os.Stdout)
|
||||||
|
if err != nil {
|
||||||
|
fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = generate.AddSubcommand(app, os.Stdout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatal(err.Error())
|
fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
10
v2/go.mod
10
v2/go.mod
@@ -3,15 +3,23 @@ module github.com/wailsapp/wails/v2
|
|||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1
|
||||||
|
github.com/fatih/structtag v1.2.0
|
||||||
github.com/fsnotify/fsnotify v1.4.9
|
github.com/fsnotify/fsnotify v1.4.9
|
||||||
|
github.com/imdario/mergo v0.3.11
|
||||||
github.com/leaanthony/clir v1.0.4
|
github.com/leaanthony/clir v1.0.4
|
||||||
github.com/leaanthony/gosod v0.0.4
|
github.com/leaanthony/gosod v0.0.4
|
||||||
github.com/leaanthony/slicer v1.4.1
|
github.com/leaanthony/slicer v1.5.0
|
||||||
github.com/matryer/is v1.4.0
|
github.com/matryer/is v1.4.0
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.4
|
github.com/olekukonko/tablewriter v0.0.4
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/tdewolff/minify v2.3.6+incompatible
|
||||||
|
github.com/tdewolff/parse v2.3.4+incompatible // indirect
|
||||||
|
github.com/tdewolff/test v1.0.6 // indirect
|
||||||
github.com/xyproto/xpm v1.2.1
|
github.com/xyproto/xpm v1.2.1
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202
|
golang.org/x/net v0.0.0-20200822124328-c89045814202
|
||||||
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
|
||||||
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82
|
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82
|
||||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
||||||
nhooyr.io/websocket v1.8.6
|
nhooyr.io/websocket v1.8.6
|
||||||
|
|||||||
20
v2/go.sum
20
v2/go.sum
@@ -1,6 +1,8 @@
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||||
|
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
@@ -29,6 +31,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||||
|
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eTO0Q8=
|
github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eTO0Q8=
|
||||||
@@ -40,8 +44,8 @@ github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU
|
|||||||
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||||
github.com/leaanthony/gosod v0.0.4 h1:v4hepo4IyL8E8c9qzDsvYcA0KGh7Npf8As74K5ibQpI=
|
github.com/leaanthony/gosod v0.0.4 h1:v4hepo4IyL8E8c9qzDsvYcA0KGh7Npf8As74K5ibQpI=
|
||||||
github.com/leaanthony/gosod v0.0.4/go.mod h1:nGMCb1PJfXwBDbOAike78jEYlpqge+xUKFf0iBKjKxU=
|
github.com/leaanthony/gosod v0.0.4/go.mod h1:nGMCb1PJfXwBDbOAike78jEYlpqge+xUKFf0iBKjKxU=
|
||||||
github.com/leaanthony/slicer v1.4.1 h1:X/SmRIDhkUAolP79mSTO0jTcVX1k504PJBqvV6TwP0w=
|
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
|
||||||
github.com/leaanthony/slicer v1.4.1/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||||
@@ -58,12 +62,20 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
|
|||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
||||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo=
|
||||||
|
github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs=
|
||||||
|
github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38=
|
||||||
|
github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ=
|
||||||
|
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
|
||||||
|
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
@@ -89,6 +101,8 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
|
||||||
|
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@@ -110,5 +124,7 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
|||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
|
nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
|
||||||
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||||
|
|||||||
@@ -5,6 +5,5 @@ package app
|
|||||||
// Init initialises the application for a debug environment
|
// Init initialises the application for a debug environment
|
||||||
func (a *App) Init() error {
|
func (a *App) Init() error {
|
||||||
a.debug = true
|
a.debug = true
|
||||||
println("Initialising debug options")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ package app
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/features"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
// App defines a Wails application structure
|
// App defines a Wails application structure
|
||||||
@@ -22,12 +22,10 @@ type App struct {
|
|||||||
|
|
||||||
// Indicates if the app is running in debug mode
|
// Indicates if the app is running in debug mode
|
||||||
debug bool
|
debug bool
|
||||||
|
|
||||||
Features *features.Features
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateApp returns a null application
|
// CreateApp returns a null application
|
||||||
func CreateApp(options *Options) *App {
|
func CreateApp(options *options.App) *App {
|
||||||
return &App{}
|
return &App{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,16 +3,15 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/binding"
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
"github.com/wailsapp/wails/v2/internal/features"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
"github.com/wailsapp/wails/v2/internal/signal"
|
"github.com/wailsapp/wails/v2/internal/signal"
|
||||||
"github.com/wailsapp/wails/v2/internal/subsystem"
|
"github.com/wailsapp/wails/v2/internal/subsystem"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// App defines a Wails application structure
|
// App defines a Wails application structure
|
||||||
@@ -21,6 +20,7 @@ type App struct {
|
|||||||
servicebus *servicebus.ServiceBus
|
servicebus *servicebus.ServiceBus
|
||||||
logger *logger.Logger
|
logger *logger.Logger
|
||||||
signal *signal.Manager
|
signal *signal.Manager
|
||||||
|
options *options.App
|
||||||
|
|
||||||
// Subsystems
|
// Subsystems
|
||||||
log *subsystem.Log
|
log *subsystem.Log
|
||||||
@@ -36,46 +36,31 @@ type App struct {
|
|||||||
// This is our binding DB
|
// This is our binding DB
|
||||||
bindings *binding.Bindings
|
bindings *binding.Bindings
|
||||||
|
|
||||||
// Feature flags
|
// LogLevel Store
|
||||||
Features *features.Features
|
loglevelStore *runtime.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create App
|
// Create App
|
||||||
func CreateApp(options *Options) *App {
|
func CreateApp(options *options.App) *App {
|
||||||
|
|
||||||
// Merge default options
|
// Merge default options
|
||||||
options.mergeDefaults()
|
options.MergeDefaults()
|
||||||
|
|
||||||
// Set up logger
|
// Set up logger
|
||||||
myLogger := logger.New(os.Stdout)
|
myLogger := logger.New(options.Logger)
|
||||||
myLogger.SetLogLevel(logger.TRACE)
|
myLogger.SetLogLevel(options.LogLevel)
|
||||||
|
|
||||||
window := ffenestri.NewApplicationWithConfig(&ffenestri.Config{
|
window := ffenestri.NewApplicationWithConfig(options, myLogger)
|
||||||
Title: options.Title,
|
|
||||||
Width: options.Width,
|
|
||||||
Height: options.Height,
|
|
||||||
MinWidth: options.MinWidth,
|
|
||||||
MinHeight: options.MinHeight,
|
|
||||||
MaxWidth: options.MaxWidth,
|
|
||||||
MaxHeight: options.MaxHeight,
|
|
||||||
Frameless: options.Frameless,
|
|
||||||
StartHidden: options.StartHidden,
|
|
||||||
|
|
||||||
// This should be controlled by the compile time flags...
|
|
||||||
DevTools: true,
|
|
||||||
|
|
||||||
Resizable: !options.DisableResize,
|
|
||||||
Fullscreen: options.Fullscreen,
|
|
||||||
}, myLogger)
|
|
||||||
|
|
||||||
result := &App{
|
result := &App{
|
||||||
window: window,
|
window: window,
|
||||||
servicebus: servicebus.New(myLogger),
|
servicebus: servicebus.New(myLogger),
|
||||||
logger: myLogger,
|
logger: myLogger,
|
||||||
bindings: binding.NewBindings(myLogger),
|
bindings: binding.NewBindings(myLogger),
|
||||||
Features: features.New(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.options = options
|
||||||
|
|
||||||
// Initialise the app
|
// Initialise the app
|
||||||
result.Init()
|
result.Init()
|
||||||
|
|
||||||
@@ -106,6 +91,9 @@ func (a *App) Run() error {
|
|||||||
a.runtime = runtime
|
a.runtime = runtime
|
||||||
a.runtime.Start()
|
a.runtime.Start()
|
||||||
|
|
||||||
|
// Application Stores
|
||||||
|
a.loglevelStore = a.runtime.GoRuntime().Store.New("loglevel", a.options.LogLevel)
|
||||||
|
|
||||||
// Start the binding subsystem
|
// Start the binding subsystem
|
||||||
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, a.runtime.GoRuntime())
|
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, a.runtime.GoRuntime())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -115,7 +103,7 @@ func (a *App) Run() error {
|
|||||||
a.binding.Start()
|
a.binding.Start()
|
||||||
|
|
||||||
// Start the logging subsystem
|
// Start the logging subsystem
|
||||||
log, err := subsystem.NewLog(a.servicebus, a.logger)
|
log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -139,7 +127,7 @@ func (a *App) Run() error {
|
|||||||
a.event.Start()
|
a.event.Start()
|
||||||
|
|
||||||
// Start the call subsystem
|
// Start the call subsystem
|
||||||
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB())
|
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -152,7 +140,7 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := a.window.Run(dispatcher, bindingDump, a.Features)
|
result := a.window.Run(dispatcher, bindingDump)
|
||||||
a.logger.Trace("Ffenestri.Run() exited")
|
a.logger.Trace("Ffenestri.Run() exited")
|
||||||
a.servicebus.Stop()
|
a.servicebus.Stop()
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"github.com/leaanthony/clir"
|
"github.com/leaanthony/clir"
|
||||||
"github.com/wailsapp/wails/v2/internal/binding"
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
"github.com/wailsapp/wails/v2/internal/features"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||||
@@ -44,9 +43,6 @@ type App struct {
|
|||||||
servicebus *servicebus.ServiceBus
|
servicebus *servicebus.ServiceBus
|
||||||
|
|
||||||
debug bool
|
debug bool
|
||||||
|
|
||||||
// Feature flags
|
|
||||||
Features *features.Features
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create App
|
// Create App
|
||||||
@@ -67,7 +63,6 @@ func CreateApp(options *Options) *App {
|
|||||||
MinHeight: options.MinHeight,
|
MinHeight: options.MinHeight,
|
||||||
MaxWidth: options.MaxWidth,
|
MaxWidth: options.MaxWidth,
|
||||||
MaxHeight: options.MaxHeight,
|
MaxHeight: options.MaxHeight,
|
||||||
Frameless: options.Frameless,
|
|
||||||
StartHidden: options.StartHidden,
|
StartHidden: options.StartHidden,
|
||||||
|
|
||||||
// This should be controlled by the compile time flags...
|
// This should be controlled by the compile time flags...
|
||||||
@@ -191,7 +186,7 @@ func (a *App) Run() error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
result := a.window.Run(dispatcher, bindingDump, a.Features)
|
result := a.window.Run(dispatcher, bindingDump)
|
||||||
a.servicebus.Stop()
|
a.servicebus.Stop()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
// Options for creating the App
|
|
||||||
type Options struct {
|
|
||||||
Title string
|
|
||||||
Width int
|
|
||||||
Height int
|
|
||||||
DisableResize bool
|
|
||||||
Fullscreen bool
|
|
||||||
Frameless bool
|
|
||||||
MinWidth int
|
|
||||||
MinHeight int
|
|
||||||
MaxWidth int
|
|
||||||
MaxHeight int
|
|
||||||
StartHidden bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// mergeDefaults will set the minimum default values for an application
|
|
||||||
func (o *Options) mergeDefaults() {
|
|
||||||
|
|
||||||
// Create a default title
|
|
||||||
if len(o.Title) == 0 {
|
|
||||||
o.Title = "My Wails App"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default width
|
|
||||||
if o.Width == 0 {
|
|
||||||
o.Width = 1024
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default height
|
|
||||||
if o.Height == 0 {
|
|
||||||
o.Height = 768
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package binding
|
package binding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -34,7 +35,7 @@ func (b *BoundMethod) VerifyWailsInit() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check input type
|
// Check input type
|
||||||
if !b.Inputs[0].IsType("*goruntime.Runtime") {
|
if !b.Inputs[0].IsType("*runtime.Runtime") {
|
||||||
return fmt.Errorf("invalid method signature for %s: expected `WailsInit(*wails.Runtime) error`", b.Name)
|
return fmt.Errorf("invalid method signature for %s: expected `WailsInit(*wails.Runtime) error`", b.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +79,26 @@ func (b *BoundMethod) OutputCount() int {
|
|||||||
return len(b.Outputs)
|
return len(b.Outputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseArgs method converts the input json into the types expected by the method
|
||||||
|
func (b *BoundMethod) ParseArgs(args []json.RawMessage) ([]interface{}, error) {
|
||||||
|
|
||||||
|
result := make([]interface{}, b.InputCount())
|
||||||
|
for index, arg := range args {
|
||||||
|
typ := b.Inputs[index].reflectType
|
||||||
|
inputValue := reflect.New(typ).Interface()
|
||||||
|
err := json.Unmarshal(arg, inputValue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if inputValue == nil {
|
||||||
|
result[index] = reflect.Zero(typ).Interface()
|
||||||
|
} else {
|
||||||
|
result[index] = reflect.ValueOf(inputValue).Elem().Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Call will attempt to call this bound method with the given args
|
// Call will attempt to call this bound method with the given args
|
||||||
func (b *BoundMethod) Call(args []interface{}) (interface{}, error) {
|
func (b *BoundMethod) Call(args []interface{}) (interface{}, error) {
|
||||||
// Check inputs
|
// Check inputs
|
||||||
@@ -94,17 +115,8 @@ func (b *BoundMethod) Call(args []interface{}) (interface{}, error) {
|
|||||||
|
|
||||||
// Iterate over given arguments
|
// Iterate over given arguments
|
||||||
for index, arg := range args {
|
for index, arg := range args {
|
||||||
|
|
||||||
// Attempt to convert the argument to the type expected by the method
|
|
||||||
value, err := convertArgToValue(arg, b.Inputs[index])
|
|
||||||
|
|
||||||
// If it fails, return a suitable error
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("%s (parameter %d): %s", b.Name, index+1, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the converted argument
|
// Save the converted argument
|
||||||
callArgs[index] = value
|
callArgs[index] = reflect.ValueOf(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do the call
|
// Do the call
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package binding
|
package binding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
@@ -67,6 +68,8 @@ func getMethods(value interface{}) ([]*BoundMethod, error) {
|
|||||||
boundMethod.Inputs = inputs
|
boundMethod.Inputs = inputs
|
||||||
|
|
||||||
// Iterate outputs
|
// Iterate outputs
|
||||||
|
// TODO: Determine what to do about limiting return types
|
||||||
|
// especially around errors.
|
||||||
outputParamCount := methodType.NumOut()
|
outputParamCount := methodType.NumOut()
|
||||||
var outputs []*Parameter
|
var outputs []*Parameter
|
||||||
for outputIndex := 0; outputIndex < outputParamCount; outputIndex++ {
|
for outputIndex := 0; outputIndex < outputParamCount; outputIndex++ {
|
||||||
@@ -84,7 +87,7 @@ func getMethods(value interface{}) ([]*BoundMethod, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// convertArgToValue
|
// convertArgToValue
|
||||||
func convertArgToValue(input interface{}, target *Parameter) (result reflect.Value, err error) {
|
func convertArgToValue(input json.RawMessage, target *Parameter) (result reflect.Value, err error) {
|
||||||
|
|
||||||
// Catch type conversion panics thrown by convert
|
// Catch type conversion panics thrown by convert
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
package features
|
|
||||||
|
|
||||||
// Features holds generic and platform specific feature flags
|
|
||||||
type Features struct {
|
|
||||||
Linux *Linux
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new Features object
|
|
||||||
func New() *Features {
|
|
||||||
return &Features{
|
|
||||||
Linux: &Linux{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
package features
|
|
||||||
|
|
||||||
// Linux holds linux specific feature flags
|
|
||||||
type Linux struct {
|
|
||||||
}
|
|
||||||
62
v2/internal/ffenestri/README.md
Normal file
62
v2/internal/ffenestri/README.md
Normal file
File diff suppressed because one or more lines are too long
@@ -1,23 +0,0 @@
|
|||||||
// +build linux
|
|
||||||
|
|
||||||
package ffenestri
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
#cgo linux CFLAGS: -DFFENESTRI_LINUX=1
|
|
||||||
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "ffenestri.h"
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import "github.com/wailsapp/wails/v2/internal/features"
|
|
||||||
|
|
||||||
func (a *Application) processOSFeatureFlags(features *features.Features) {
|
|
||||||
|
|
||||||
// Process Linux features
|
|
||||||
// linux := features.Linux
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -5,9 +5,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/features"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -15,6 +15,9 @@ import (
|
|||||||
#cgo linux CFLAGS: -DFFENESTRI_LINUX=1
|
#cgo linux CFLAGS: -DFFENESTRI_LINUX=1
|
||||||
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
|
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
|
||||||
|
|
||||||
|
#cgo darwin CFLAGS: -DFFENESTRI_DARWIN=1
|
||||||
|
#cgo darwin LDFLAGS: -framework WebKit -lobjc
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "ffenestri.h"
|
#include "ffenestri.h"
|
||||||
|
|
||||||
@@ -26,36 +29,9 @@ import "C"
|
|||||||
// TODO: move to compile time.
|
// TODO: move to compile time.
|
||||||
var DEBUG bool = true
|
var DEBUG bool = true
|
||||||
|
|
||||||
// Config defines how our application should be configured
|
|
||||||
type Config struct {
|
|
||||||
Title string
|
|
||||||
Width int
|
|
||||||
Height int
|
|
||||||
MinWidth int
|
|
||||||
MinHeight int
|
|
||||||
MaxWidth int
|
|
||||||
MaxHeight int
|
|
||||||
DevTools bool
|
|
||||||
Resizable bool
|
|
||||||
Fullscreen bool
|
|
||||||
Frameless bool
|
|
||||||
StartHidden bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultConfig = &Config{
|
|
||||||
Title: "My Wails App",
|
|
||||||
Width: 800,
|
|
||||||
Height: 600,
|
|
||||||
DevTools: true,
|
|
||||||
Resizable: true,
|
|
||||||
Fullscreen: false,
|
|
||||||
Frameless: false,
|
|
||||||
StartHidden: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Application is our main application object
|
// Application is our main application object
|
||||||
type Application struct {
|
type Application struct {
|
||||||
config *Config
|
config *options.App
|
||||||
memory []unsafe.Pointer
|
memory []unsafe.Pointer
|
||||||
|
|
||||||
// This is the main app pointer
|
// This is the main app pointer
|
||||||
@@ -80,7 +56,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewApplicationWithConfig creates a new application based on the given config
|
// NewApplicationWithConfig creates a new application based on the given config
|
||||||
func NewApplicationWithConfig(config *Config, logger *logger.Logger) *Application {
|
func NewApplicationWithConfig(config *options.App, logger *logger.Logger) *Application {
|
||||||
return &Application{
|
return &Application{
|
||||||
config: config,
|
config: config,
|
||||||
logger: logger.CustomLogger("Ffenestri"),
|
logger: logger.CustomLogger("Ffenestri"),
|
||||||
@@ -90,7 +66,7 @@ func NewApplicationWithConfig(config *Config, logger *logger.Logger) *Applicatio
|
|||||||
// NewApplication creates a new Application with the default config
|
// NewApplication creates a new Application with the default config
|
||||||
func NewApplication(logger *logger.Logger) *Application {
|
func NewApplication(logger *logger.Logger) *Application {
|
||||||
return &Application{
|
return &Application{
|
||||||
config: defaultConfig,
|
config: options.Default,
|
||||||
logger: logger.CustomLogger("Ffenestri"),
|
logger: logger.CustomLogger("Ffenestri"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,16 +99,25 @@ type DispatchClient interface {
|
|||||||
SendMessage(string)
|
SendMessage(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func intToColour(colour int) (C.int, C.int, C.int, C.int) {
|
||||||
|
var alpha = C.int(colour & 0xFF)
|
||||||
|
var blue = C.int((colour >> 8) & 0xFF)
|
||||||
|
var green = C.int((colour >> 16) & 0xFF)
|
||||||
|
var red = C.int((colour >> 24) & 0xFF)
|
||||||
|
return red, green, blue, alpha
|
||||||
|
}
|
||||||
|
|
||||||
// Run the application
|
// Run the application
|
||||||
func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, features *features.Features) error {
|
func (a *Application) Run(incomingDispatcher Dispatcher, bindings string) error {
|
||||||
title := a.string2CString(a.config.Title)
|
title := a.string2CString(a.config.Title)
|
||||||
width := C.int(a.config.Width)
|
width := C.int(a.config.Width)
|
||||||
height := C.int(a.config.Height)
|
height := C.int(a.config.Height)
|
||||||
resizable := a.bool2Cint(a.config.Resizable)
|
resizable := a.bool2Cint(!a.config.DisableResize)
|
||||||
devtools := a.bool2Cint(a.config.DevTools)
|
devtools := a.bool2Cint(a.config.DevTools)
|
||||||
fullscreen := a.bool2Cint(a.config.Fullscreen)
|
fullscreen := a.bool2Cint(a.config.Fullscreen)
|
||||||
startHidden := a.bool2Cint(a.config.StartHidden)
|
startHidden := a.bool2Cint(a.config.StartHidden)
|
||||||
app := C.NewApplication(title, width, height, resizable, devtools, fullscreen, startHidden)
|
logLevel := C.int(a.config.LogLevel)
|
||||||
|
app := C.NewApplication(title, width, height, resizable, devtools, fullscreen, startHidden, logLevel)
|
||||||
|
|
||||||
// Save app reference
|
// Save app reference
|
||||||
a.app = unsafe.Pointer(app)
|
a.app = unsafe.Pointer(app)
|
||||||
@@ -150,9 +135,14 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, featur
|
|||||||
// Set debug if needed
|
// Set debug if needed
|
||||||
C.SetDebug(app, a.bool2Cint(DEBUG))
|
C.SetDebug(app, a.bool2Cint(DEBUG))
|
||||||
|
|
||||||
// Set Frameless
|
// TODO: Move frameless to Linux options
|
||||||
if a.config.Frameless {
|
// if a.config.Frameless {
|
||||||
C.DisableFrame(a.app)
|
// C.DisableFrame(a.app)
|
||||||
|
// }
|
||||||
|
|
||||||
|
if a.config.RGBA != 0 {
|
||||||
|
r, g, b, alpha := intToColour(a.config.RGBA)
|
||||||
|
C.SetColour(a.app, r, g, b, alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape bindings so C doesn't freak out
|
// Escape bindings so C doesn't freak out
|
||||||
@@ -161,13 +151,13 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, featur
|
|||||||
// Set bindings
|
// Set bindings
|
||||||
C.SetBindings(app, a.string2CString(bindings))
|
C.SetBindings(app, a.string2CString(bindings))
|
||||||
|
|
||||||
// Process feature flags
|
|
||||||
a.processFeatureFlags(features)
|
|
||||||
|
|
||||||
// save the dispatcher in a package variable so that the C callbacks
|
// save the dispatcher in a package variable so that the C callbacks
|
||||||
// can access it
|
// can access it
|
||||||
dispatcher = incomingDispatcher.RegisterClient(newClient(a))
|
dispatcher = incomingDispatcher.RegisterClient(newClient(a))
|
||||||
|
|
||||||
|
// Process platform settings
|
||||||
|
a.processPlatformSettings()
|
||||||
|
|
||||||
// Check we could initialise the application
|
// Check we could initialise the application
|
||||||
if app != nil {
|
if app != nil {
|
||||||
// Yes - Save memory reference and run app, cleaning up afterwards
|
// Yes - Save memory reference and run app, cleaning up afterwards
|
||||||
@@ -189,11 +179,3 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, featur
|
|||||||
func messageFromWindowCallback(data *C.char) {
|
func messageFromWindowCallback(data *C.char) {
|
||||||
dispatcher.DispatchMessage(C.GoString(data))
|
dispatcher.DispatchMessage(C.GoString(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Application) processFeatureFlags(features *features.Features) {
|
|
||||||
|
|
||||||
// Process generic features
|
|
||||||
|
|
||||||
// Process OS Specific flags
|
|
||||||
a.processOSFeatureFlags(features)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
extern void *NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden);
|
extern void *NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel);
|
||||||
extern void SetMinWindowSize(void *app, int minWidth, int minHeight);
|
extern void SetMinWindowSize(void *app, int minWidth, int minHeight);
|
||||||
extern void SetMaxWindowSize(void *app, int maxWidth, int maxHeight);
|
extern void SetMaxWindowSize(void *app, int maxWidth, int maxHeight);
|
||||||
extern void Run(void *app, int argc, char **argv);
|
extern void Run(void *app, int argc, char **argv);
|
||||||
@@ -16,18 +16,20 @@ extern void Show(void *app);
|
|||||||
extern void Center(void *app);
|
extern void Center(void *app);
|
||||||
extern void Maximise(void *app);
|
extern void Maximise(void *app);
|
||||||
extern void Unmaximise(void *app);
|
extern void Unmaximise(void *app);
|
||||||
|
extern void ToggleMaximise(void *app);
|
||||||
extern void Minimise(void *app);
|
extern void Minimise(void *app);
|
||||||
extern void Unminimise(void *app);
|
extern void Unminimise(void *app);
|
||||||
|
extern void ToggleMinimise(void *app);
|
||||||
|
extern void SetColour(void *app, int red, int green, int blue, int alpha);
|
||||||
extern void SetSize(void *app, int width, int height);
|
extern void SetSize(void *app, int width, int height);
|
||||||
extern void SetPosition(void *app, int x, int y);
|
extern void SetPosition(void *app, int x, int y);
|
||||||
extern void Quit(void *app);
|
extern void Quit(void *app);
|
||||||
extern void SetTitle(void *app, const char *title);
|
extern void SetTitle(void *app, const char *title);
|
||||||
extern void Fullscreen(void *app);
|
extern void Fullscreen(void *app);
|
||||||
extern void UnFullscreen(void *app);
|
extern void UnFullscreen(void *app);
|
||||||
extern int SetColour(void *app, const char *colourString);
|
extern void ToggleFullscreen(void *app);
|
||||||
extern void DisableFrame(void *app);
|
extern void DisableFrame(void *app);
|
||||||
extern char *SaveFileDialog(void *appPointer, char *title, char *filter);
|
extern void OpenDialog(void *appPointer, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int allowFiles, int allowDirs, int allowMultiple, int showHiddenFiles, int canCreateDirectories, int resolveAliases, int treatPackagesAsDirectories);
|
||||||
extern char *OpenFileDialog(void *appPointer, char *title, char *filter);
|
extern void SaveDialog(void *appPointer, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int showHiddenFiles, int canCreateDirectories, int treatPackagesAsDirectories);
|
||||||
extern char *OpenDirectoryDialog(void *appPointer, char *title, char *filter);
|
extern void DarkModeEnabled(void *appPointer, char *callbackID);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import "C"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client is our implentation of messageDispatcher.Client
|
// Client is our implentation of messageDispatcher.Client
|
||||||
@@ -114,46 +114,43 @@ func (c *Client) WindowSize(width int, height int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WindowSetColour sets the window colour
|
// WindowSetColour sets the window colour
|
||||||
func (c *Client) WindowSetColour(colour string) bool {
|
func (c *Client) WindowSetColour(colour int) {
|
||||||
result := C.SetColour(c.app.app, c.app.string2CString(colour))
|
r, g, b, a := intToColour(colour)
|
||||||
return result == 1
|
C.SetColour(c.app.app, r, g, b, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenFileDialog will open a file dialog with the given title
|
// OpenDialog will open a dialog with the given title and filter
|
||||||
func (c *Client) OpenFileDialog(title string, filter string) string {
|
func (c *Client) OpenDialog(dialogOptions *options.OpenDialog, callbackID string) {
|
||||||
|
C.OpenDialog(c.app.app,
|
||||||
cstring := C.OpenFileDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter))
|
c.app.string2CString(callbackID),
|
||||||
var result string
|
c.app.string2CString(dialogOptions.Title),
|
||||||
if cstring != nil {
|
c.app.string2CString(dialogOptions.Filters),
|
||||||
result = C.GoString(cstring)
|
c.app.string2CString(dialogOptions.DefaultFilename),
|
||||||
// Free the C string that was allocated by the dialog
|
c.app.string2CString(dialogOptions.DefaultDirectory),
|
||||||
C.free(unsafe.Pointer(cstring))
|
c.app.bool2Cint(dialogOptions.AllowFiles),
|
||||||
}
|
c.app.bool2Cint(dialogOptions.AllowDirectories),
|
||||||
return result
|
c.app.bool2Cint(dialogOptions.AllowMultiple),
|
||||||
|
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
|
||||||
|
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
|
||||||
|
c.app.bool2Cint(dialogOptions.ResolveAliases),
|
||||||
|
c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveFileDialog will open a save file dialog with the given title
|
// SaveDialog will open a dialog with the given title and filter
|
||||||
func (c *Client) SaveFileDialog(title string, filter string) string {
|
func (c *Client) SaveDialog(dialogOptions *options.SaveDialog, callbackID string) {
|
||||||
|
C.SaveDialog(c.app.app,
|
||||||
cstring := C.SaveFileDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter))
|
c.app.string2CString(callbackID),
|
||||||
var result string
|
c.app.string2CString(dialogOptions.Title),
|
||||||
if cstring != nil {
|
c.app.string2CString(dialogOptions.Filters),
|
||||||
result = C.GoString(cstring)
|
c.app.string2CString(dialogOptions.DefaultFilename),
|
||||||
// Free the C string that was allocated by the dialog
|
c.app.string2CString(dialogOptions.DefaultDirectory),
|
||||||
C.free(unsafe.Pointer(cstring))
|
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
|
||||||
}
|
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
|
||||||
return result
|
c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenDirectoryDialog will open a directory dialog with the given title
|
func (c *Client) DarkModeEnabled(callbackID string) {
|
||||||
func (c *Client) OpenDirectoryDialog(title string, filter string) string {
|
C.DarkModeEnabled(c.app.app, c.app.string2CString(callbackID))
|
||||||
|
|
||||||
cstring := C.OpenDirectoryDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter))
|
|
||||||
var result string
|
|
||||||
if cstring != nil {
|
|
||||||
result = C.GoString(cstring)
|
|
||||||
// Free the C string that was allocated by the dialog
|
|
||||||
C.free(unsafe.Pointer(cstring))
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|||||||
1050
v2/internal/ffenestri/ffenestri_darwin.c
Normal file
1050
v2/internal/ffenestri/ffenestri_darwin.c
Normal file
File diff suppressed because it is too large
Load Diff
67
v2/internal/ffenestri/ffenestri_darwin.go
Normal file
67
v2/internal/ffenestri/ffenestri_darwin.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package ffenestri
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo darwin CFLAGS: -DFFENESTRI_DARWIN=1
|
||||||
|
#cgo darwin LDFLAGS: -framework WebKit -lobjc
|
||||||
|
|
||||||
|
extern void TitlebarAppearsTransparent(void *);
|
||||||
|
extern void HideTitle(void *);
|
||||||
|
extern void HideTitleBar(void *);
|
||||||
|
extern void FullSizeContent(void *);
|
||||||
|
extern void UseToolbar(void *);
|
||||||
|
extern void HideToolbarSeparator(void *);
|
||||||
|
extern void DisableFrame(void *);
|
||||||
|
extern void SetAppearance(void *, const char *);
|
||||||
|
extern void WebviewIsTransparent(void *);
|
||||||
|
extern void SetWindowBackgroundIsTranslucent(void *);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func (a *Application) processPlatformSettings() {
|
||||||
|
|
||||||
|
mac := a.config.Mac
|
||||||
|
titlebar := mac.TitleBar
|
||||||
|
|
||||||
|
// HideTitle
|
||||||
|
if titlebar.HideTitle {
|
||||||
|
C.HideTitle(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HideTitleBar
|
||||||
|
if titlebar.HideTitleBar {
|
||||||
|
C.HideTitleBar(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full Size Content
|
||||||
|
if titlebar.FullSizeContent {
|
||||||
|
C.FullSizeContent(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toolbar
|
||||||
|
if titlebar.UseToolbar {
|
||||||
|
C.UseToolbar(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
if titlebar.HideToolbarSeparator {
|
||||||
|
C.HideToolbarSeparator(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
if titlebar.TitlebarAppearsTransparent {
|
||||||
|
C.TitlebarAppearsTransparent(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process window Appearance
|
||||||
|
if mac.Appearance != "" {
|
||||||
|
C.SetAppearance(a.app, a.string2CString(string(mac.Appearance)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the webview should be transparent
|
||||||
|
if mac.WebviewIsTransparent {
|
||||||
|
C.WebviewIsTransparent(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if window should be translucent
|
||||||
|
if mac.WindowBackgroundIsTranslucent {
|
||||||
|
C.SetWindowBackgroundIsTranslucent(a.app)
|
||||||
|
}
|
||||||
|
}
|
||||||
1383
v2/internal/ffenestri/json.c
Normal file
1383
v2/internal/ffenestri/json.c
Normal file
File diff suppressed because it is too large
Load Diff
119
v2/internal/ffenestri/json.h
Normal file
119
v2/internal/ffenestri/json.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
Source: http://git.ozlabs.org/?p=ccan;a=tree;f=ccan/json;hb=HEAD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CCAN_JSON_H
|
||||||
|
#define CCAN_JSON_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
JSON_NULL,
|
||||||
|
JSON_BOOL,
|
||||||
|
JSON_STRING,
|
||||||
|
JSON_NUMBER,
|
||||||
|
JSON_ARRAY,
|
||||||
|
JSON_OBJECT,
|
||||||
|
} JsonTag;
|
||||||
|
|
||||||
|
typedef struct JsonNode JsonNode;
|
||||||
|
|
||||||
|
struct JsonNode
|
||||||
|
{
|
||||||
|
/* only if parent is an object or array (NULL otherwise) */
|
||||||
|
JsonNode *parent;
|
||||||
|
JsonNode *prev, *next;
|
||||||
|
|
||||||
|
/* only if parent is an object (NULL otherwise) */
|
||||||
|
char *key; /* Must be valid UTF-8. */
|
||||||
|
|
||||||
|
JsonTag tag;
|
||||||
|
union {
|
||||||
|
/* JSON_BOOL */
|
||||||
|
bool bool_;
|
||||||
|
|
||||||
|
/* JSON_STRING */
|
||||||
|
char *string_; /* Must be valid UTF-8. */
|
||||||
|
|
||||||
|
/* JSON_NUMBER */
|
||||||
|
double number_;
|
||||||
|
|
||||||
|
/* JSON_ARRAY */
|
||||||
|
/* JSON_OBJECT */
|
||||||
|
struct {
|
||||||
|
JsonNode *head, *tail;
|
||||||
|
} children;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/*** Encoding, decoding, and validation ***/
|
||||||
|
|
||||||
|
JsonNode *json_decode (const char *json);
|
||||||
|
char *json_encode (const JsonNode *node);
|
||||||
|
char *json_encode_string (const char *str);
|
||||||
|
char *json_stringify (const JsonNode *node, const char *space);
|
||||||
|
void json_delete (JsonNode *node);
|
||||||
|
|
||||||
|
bool json_validate (const char *json);
|
||||||
|
|
||||||
|
/*** Lookup and traversal ***/
|
||||||
|
|
||||||
|
JsonNode *json_find_element (JsonNode *array, int index);
|
||||||
|
JsonNode *json_find_member (JsonNode *object, const char *key);
|
||||||
|
|
||||||
|
JsonNode *json_first_child (const JsonNode *node);
|
||||||
|
|
||||||
|
#define json_foreach(i, object_or_array) \
|
||||||
|
for ((i) = json_first_child(object_or_array); \
|
||||||
|
(i) != NULL; \
|
||||||
|
(i) = (i)->next)
|
||||||
|
|
||||||
|
/*** Construction and manipulation ***/
|
||||||
|
|
||||||
|
JsonNode *json_mknull(void);
|
||||||
|
JsonNode *json_mkbool(bool b);
|
||||||
|
JsonNode *json_mkstring(const char *s);
|
||||||
|
JsonNode *json_mknumber(double n);
|
||||||
|
JsonNode *json_mkarray(void);
|
||||||
|
JsonNode *json_mkobject(void);
|
||||||
|
|
||||||
|
void json_append_element(JsonNode *array, JsonNode *element);
|
||||||
|
void json_prepend_element(JsonNode *array, JsonNode *element);
|
||||||
|
void json_append_member(JsonNode *object, const char *key, JsonNode *value);
|
||||||
|
void json_prepend_member(JsonNode *object, const char *key, JsonNode *value);
|
||||||
|
|
||||||
|
void json_remove_from_parent(JsonNode *node);
|
||||||
|
|
||||||
|
/*** Debugging ***/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for structure and encoding problems in a JsonNode or its descendents.
|
||||||
|
*
|
||||||
|
* If a problem is detected, return false, writing a description of the problem
|
||||||
|
* to errmsg (unless errmsg is NULL).
|
||||||
|
*/
|
||||||
|
bool json_check(const JsonNode *node, char errmsg[256]);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -20,6 +20,17 @@ func LocalDirectory() string {
|
|||||||
return filepath.Dir(thisFile)
|
return filepath.Dir(thisFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RelativeToCwd returns an absolute path based on the cwd
|
||||||
|
// and the given relative path
|
||||||
|
func RelativeToCwd(relativePath string) (string, error) {
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.Join(cwd, relativePath), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Mkdir will create the given directory
|
// Mkdir will create the given directory
|
||||||
func Mkdir(dirname string) error {
|
func Mkdir(dirname string) error {
|
||||||
return os.Mkdir(dirname, 0755)
|
return os.Mkdir(dirname, 0755)
|
||||||
@@ -169,3 +180,23 @@ func GetSubdirectories(rootDir string) (*slicer.StringSlicer, error) {
|
|||||||
})
|
})
|
||||||
return &result, err
|
return &result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DirIsEmpty(dir string) (bool, error) {
|
||||||
|
|
||||||
|
if !DirExists(dir) {
|
||||||
|
return false, fmt.Errorf("DirIsEmpty called with a non-existant directory: %s", dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CREDIT: https://stackoverflow.com/a/30708914/8325411
|
||||||
|
f, err := os.Open(dir)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = f.Readdirnames(1) // Or f.Readdir(1)
|
||||||
|
if err == io.EOF {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, err // Either not empty or error, suits both cases
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,11 +3,15 @@ package html
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/tdewolff/minify"
|
||||||
|
"github.com/tdewolff/minify/js"
|
||||||
)
|
)
|
||||||
|
|
||||||
type assetTypes struct {
|
type assetTypes struct {
|
||||||
@@ -63,6 +67,10 @@ func (a *Asset) AsCHexData() string {
|
|||||||
result = strings.ReplaceAll(result, "\n", "")
|
result = strings.ReplaceAll(result, "\n", "")
|
||||||
result = strings.ReplaceAll(result, "\r\n", "")
|
result = strings.ReplaceAll(result, "\r\n", "")
|
||||||
result = strings.ReplaceAll(result, "\n", "")
|
result = strings.ReplaceAll(result, "\n", "")
|
||||||
|
|
||||||
|
// Inject wailsloader code
|
||||||
|
result = strings.Replace(result, `</body>`, `<script id='wailsloader'>window.wailsloader = { html: true, runtime: false, userjs: false, usercss: false };var self=document.querySelector('#wailsloader');self.parentNode.removeChild(self);</script></body>`, 1)
|
||||||
|
|
||||||
url := url.URL{Path: result}
|
url := url.URL{Path: result}
|
||||||
urlString := strings.ReplaceAll(url.String(), "/", "%2f")
|
urlString := strings.ReplaceAll(url.String(), "/", "%2f")
|
||||||
|
|
||||||
@@ -84,6 +92,16 @@ func (a *Asset) AsCHexData() string {
|
|||||||
result = strings.ReplaceAll(result, ` {`, `{`)
|
result = strings.ReplaceAll(result, ` {`, `{`)
|
||||||
result = strings.ReplaceAll(result, `: `, `:`)
|
result = strings.ReplaceAll(result, `: `, `:`)
|
||||||
dataString = fmt.Sprintf("window.wails._.InjectCSS(\"%s\");", result)
|
dataString = fmt.Sprintf("window.wails._.InjectCSS(\"%s\");", result)
|
||||||
|
|
||||||
|
case AssetTypes.JS:
|
||||||
|
m := minify.New()
|
||||||
|
m.AddFunc("application/javascript", js.Minify)
|
||||||
|
var err error
|
||||||
|
dataString, err = m.String("application/javascript", a.Data+";")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
a.Data = dataString
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get byte data of the string
|
// Get byte data of the string
|
||||||
@@ -103,6 +121,7 @@ func (a *Asset) AsCHexData() string {
|
|||||||
return cdata.String()
|
return cdata.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dump will output the asset to the terminal
|
||||||
func (a *Asset) Dump() {
|
func (a *Asset) Dump() {
|
||||||
fmt.Printf("{ Type: %s, Path: %s, Data: %+v }\n", a.Type, a.Path, a.Data[:10])
|
fmt.Printf("{ Type: %s, Path: %s, Data: %+v }\n", a.Type, a.Path, a.Data[:10])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,6 +153,10 @@ func (a *AssetBundle) WriteToCFile(targetDir string) (string, error) {
|
|||||||
assetVariables := slicer.String()
|
assetVariables := slicer.String()
|
||||||
var variableName string
|
var variableName string
|
||||||
for index, asset := range a.assets {
|
for index, asset := range a.assets {
|
||||||
|
// For desktop we ignore the favicon
|
||||||
|
if asset.Type == AssetTypes.FAVICON {
|
||||||
|
continue
|
||||||
|
}
|
||||||
variableName = fmt.Sprintf("%s%d", asset.Type, index)
|
variableName = fmt.Sprintf("%s%d", asset.Type, index)
|
||||||
assetCdata := fmt.Sprintf("const unsigned char %s[]={ %s0x00 };\n", variableName, asset.AsCHexData())
|
assetCdata := fmt.Sprintf("const unsigned char %s[]={ %s0x00 };\n", variableName, asset.AsCHexData())
|
||||||
cdata.WriteString(assetCdata)
|
cdata.WriteString(assetCdata)
|
||||||
@@ -160,9 +164,9 @@ func (a *AssetBundle) WriteToCFile(targetDir string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if assetVariables.Length() > 0 {
|
if assetVariables.Length() > 0 {
|
||||||
cdata.WriteString(fmt.Sprintf("\nconst char *assets[] = { %s, 0x00 };", assetVariables.Join(", ")))
|
cdata.WriteString(fmt.Sprintf("\nconst unsigned char *assets[] = { %s, 0x00 };", assetVariables.Join(", ")))
|
||||||
} else {
|
} else {
|
||||||
cdata.WriteString("\nconst char *assets[] = { 0x00 };")
|
cdata.WriteString("\nconst unsigned char *assets[] = { 0x00 };")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save file
|
// Save file
|
||||||
@@ -187,6 +191,7 @@ func (a *AssetBundle) ConvertToAssetDB() (*assetdb.AssetDB, error) {
|
|||||||
return assetdb, nil
|
return assetdb, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dump will output the assets to the terminal
|
||||||
func (a *AssetBundle) Dump() {
|
func (a *AssetBundle) Dump() {
|
||||||
println("Assets:")
|
println("Assets:")
|
||||||
for _, asset := range a.assets {
|
for _, asset := range a.assets {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package logger
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CustomLogger defines what a user can do with a logger
|
// CustomLogger defines what a user can do with a logger
|
||||||
@@ -62,37 +61,36 @@ func (l *customLogger) Write(message string) error {
|
|||||||
// Trace level logging. Works like Sprintf.
|
// Trace level logging. Works like Sprintf.
|
||||||
func (l *customLogger) Trace(format string, args ...interface{}) error {
|
func (l *customLogger) Trace(format string, args ...interface{}) error {
|
||||||
format = fmt.Sprintf("%s | %s", l.name, format)
|
format = fmt.Sprintf("%s | %s", l.name, format)
|
||||||
return l.logger.processLogMessage(TRACE, format, args...)
|
return l.logger.Trace(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug level logging. Works like Sprintf.
|
// Debug level logging. Works like Sprintf.
|
||||||
func (l *customLogger) Debug(format string, args ...interface{}) error {
|
func (l *customLogger) Debug(format string, args ...interface{}) error {
|
||||||
format = fmt.Sprintf("%s | %s", l.name, format)
|
format = fmt.Sprintf("%s | %s", l.name, format)
|
||||||
return l.logger.processLogMessage(DEBUG, format, args...)
|
return l.logger.Debug(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info level logging. Works like Sprintf.
|
// Info level logging. Works like Sprintf.
|
||||||
func (l *customLogger) Info(format string, args ...interface{}) error {
|
func (l *customLogger) Info(format string, args ...interface{}) error {
|
||||||
format = fmt.Sprintf("%s | %s", l.name, format)
|
format = fmt.Sprintf("%s | %s", l.name, format)
|
||||||
return l.logger.processLogMessage(INFO, format, args...)
|
return l.logger.Info(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning level logging. Works like Sprintf.
|
// Warning level logging. Works like Sprintf.
|
||||||
func (l *customLogger) Warning(format string, args ...interface{}) error {
|
func (l *customLogger) Warning(format string, args ...interface{}) error {
|
||||||
format = fmt.Sprintf("%s | %s", l.name, format)
|
format = fmt.Sprintf("%s | %s", l.name, format)
|
||||||
return l.logger.processLogMessage(WARNING, format, args...)
|
return l.logger.Warning(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error level logging. Works like Sprintf.
|
// Error level logging. Works like Sprintf.
|
||||||
func (l *customLogger) Error(format string, args ...interface{}) error {
|
func (l *customLogger) Error(format string, args ...interface{}) error {
|
||||||
format = fmt.Sprintf("%s | %s", l.name, format)
|
format = fmt.Sprintf("%s | %s", l.name, format)
|
||||||
return l.logger.processLogMessage(ERROR, format, args...)
|
return l.logger.Error(format, args...)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal level logging. Works like Sprintf.
|
// Fatal level logging. Works like Sprintf.
|
||||||
func (l *customLogger) Fatal(format string, args ...interface{}) {
|
func (l *customLogger) Fatal(format string, args ...interface{}) {
|
||||||
format = fmt.Sprintf("%s | %s", l.name, format)
|
format = fmt.Sprintf("%s | %s", l.name, format)
|
||||||
l.logger.processLogMessage(FATAL, format, args...)
|
l.logger.Fatal(format, args...)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,37 +2,32 @@ package logger
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// LogLevel is an alias for the public LogLevel
|
||||||
|
type LogLevel = logger.LogLevel
|
||||||
|
|
||||||
// Logger is a utlility to log messages to a number of destinations
|
// Logger is a utlility to log messages to a number of destinations
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
writers []io.Writer
|
output logger.Logger
|
||||||
logLevel uint8
|
logLevel LogLevel
|
||||||
showLevelInLog bool
|
showLevelInLog bool
|
||||||
lock sync.RWMutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Logger. You may pass in a number of `io.Writer`s that
|
// New creates a new Logger. You may pass in a number of `io.Writer`s that
|
||||||
// are the targets for the logs
|
// are the targets for the logs
|
||||||
func New(writers ...io.Writer) *Logger {
|
func New(output logger.Logger) *Logger {
|
||||||
result := &Logger{
|
result := &Logger{
|
||||||
logLevel: INFO,
|
logLevel: logger.INFO,
|
||||||
showLevelInLog: true,
|
showLevelInLog: true,
|
||||||
}
|
output: output,
|
||||||
for _, writer := range writers {
|
|
||||||
result.AddOutput(writer)
|
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writers gets the log writers
|
|
||||||
func (l *Logger) Writers() []io.Writer {
|
|
||||||
return l.writers
|
|
||||||
}
|
|
||||||
|
|
||||||
// CustomLogger creates a new custom logger that prints out a name/id
|
// CustomLogger creates a new custom logger that prints out a name/id
|
||||||
// before the messages
|
// before the messages
|
||||||
func (l *Logger) CustomLogger(name string) CustomLogger {
|
func (l *Logger) CustomLogger(name string) CustomLogger {
|
||||||
@@ -45,99 +40,73 @@ func (l *Logger) HideLogLevel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetLogLevel sets the minimum level of logs that will be output
|
// SetLogLevel sets the minimum level of logs that will be output
|
||||||
func (l *Logger) SetLogLevel(level uint8) {
|
func (l *Logger) SetLogLevel(level LogLevel) {
|
||||||
l.logLevel = level
|
l.logLevel = level
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOutput adds the given `io.Writer` to the list of destinations
|
|
||||||
// that get logged to
|
|
||||||
func (l *Logger) AddOutput(writer io.Writer) {
|
|
||||||
l.writers = append(l.writers, writer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) write(loglevel uint8, message string) error {
|
|
||||||
|
|
||||||
// Don't print logs lower than the current log level
|
|
||||||
if loglevel < l.logLevel {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show log level text if enabled
|
|
||||||
if l.showLevelInLog {
|
|
||||||
message = mapLogLevel[loglevel] + message
|
|
||||||
}
|
|
||||||
|
|
||||||
// write out the logs
|
|
||||||
l.lock.Lock()
|
|
||||||
for _, writer := range l.writers {
|
|
||||||
_, err := writer.Write([]byte(message))
|
|
||||||
if err != nil {
|
|
||||||
l.lock.Unlock() // Because defer is slow
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
l.lock.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeln appends a newline character to the message before writing
|
|
||||||
func (l *Logger) writeln(loglevel uint8, message string) error {
|
|
||||||
return l.write(loglevel, message+"\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writeln writes directly to the output with no log level
|
// Writeln writes directly to the output with no log level
|
||||||
// Appends a carriage return to the message
|
// Appends a carriage return to the message
|
||||||
func (l *Logger) Writeln(message string) error {
|
func (l *Logger) Writeln(message string) error {
|
||||||
return l.write(BYPASS, message+"\n")
|
return l.output.Print(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write writes directly to the output with no log level
|
// Write writes directly to the output with no log level
|
||||||
func (l *Logger) Write(message string) error {
|
func (l *Logger) Write(message string) error {
|
||||||
return l.write(BYPASS, message)
|
return l.output.Print(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// processLogMessage formats the given message before writing it out
|
// Print writes directly to the output with no log level
|
||||||
func (l *Logger) processLogMessage(loglevel uint8, format string, args ...interface{}) error {
|
// Appends a carriage return to the message
|
||||||
message := fmt.Sprintf(format, args...)
|
func (l *Logger) Print(message string) error {
|
||||||
return l.writeln(loglevel, message)
|
return l.Write(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trace level logging. Works like Sprintf.
|
// Trace level logging. Works like Sprintf.
|
||||||
func (l *Logger) Trace(format string, args ...interface{}) error {
|
func (l *Logger) Trace(format string, args ...interface{}) error {
|
||||||
return l.processLogMessage(TRACE, format, args...)
|
if l.logLevel <= logger.TRACE {
|
||||||
}
|
return l.output.Trace(fmt.Sprintf(format, args...))
|
||||||
|
|
||||||
// CustomTrace returns a custom Logging function that will insert the given name before the message
|
|
||||||
func (l *Logger) CustomTrace(name string) func(format string, args ...interface{}) {
|
|
||||||
return func(format string, args ...interface{}) {
|
|
||||||
format = name + " | " + format
|
|
||||||
l.processLogMessage(TRACE, format, args...)
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug level logging. Works like Sprintf.
|
// Debug level logging. Works like Sprintf.
|
||||||
func (l *Logger) Debug(format string, args ...interface{}) error {
|
func (l *Logger) Debug(format string, args ...interface{}) error {
|
||||||
return l.processLogMessage(DEBUG, format, args...)
|
if l.logLevel <= logger.DEBUG {
|
||||||
|
return l.output.Debug(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info level logging. Works like Sprintf.
|
// Info level logging. Works like Sprintf.
|
||||||
func (l *Logger) Info(format string, args ...interface{}) error {
|
func (l *Logger) Info(format string, args ...interface{}) error {
|
||||||
return l.processLogMessage(INFO, format, args...)
|
if l.logLevel <= logger.INFO {
|
||||||
|
return l.output.Info(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning level logging. Works like Sprintf.
|
// Warning level logging. Works like Sprintf.
|
||||||
func (l *Logger) Warning(format string, args ...interface{}) error {
|
func (l *Logger) Warning(format string, args ...interface{}) error {
|
||||||
return l.processLogMessage(WARNING, format, args...)
|
if l.logLevel <= logger.WARNING {
|
||||||
|
return l.output.Warning(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error level logging. Works like Sprintf.
|
// Error level logging. Works like Sprintf.
|
||||||
func (l *Logger) Error(format string, args ...interface{}) error {
|
func (l *Logger) Error(format string, args ...interface{}) error {
|
||||||
return l.processLogMessage(ERROR, format, args...)
|
if l.logLevel <= logger.ERROR {
|
||||||
|
return l.output.Error(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal level logging. Works like Sprintf.
|
// Fatal level logging. Works like Sprintf.
|
||||||
func (l *Logger) Fatal(format string, args ...interface{}) {
|
func (l *Logger) Fatal(format string, args ...interface{}) {
|
||||||
l.processLogMessage(FATAL, format, args...)
|
err := l.output.Fatal(fmt.Sprintf(format, args...))
|
||||||
|
// Not much we can do but print it out before exiting
|
||||||
|
if err != nil {
|
||||||
|
println(err.Error())
|
||||||
|
}
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
package logger
|
|
||||||
|
|
||||||
const (
|
|
||||||
// TRACE level
|
|
||||||
TRACE uint8 = 0
|
|
||||||
|
|
||||||
// DEBUG level logging
|
|
||||||
DEBUG uint8 = 1
|
|
||||||
|
|
||||||
// INFO level logging
|
|
||||||
INFO uint8 = 2
|
|
||||||
|
|
||||||
// WARNING level logging
|
|
||||||
WARNING uint8 = 4
|
|
||||||
|
|
||||||
// ERROR level logging
|
|
||||||
ERROR uint8 = 8
|
|
||||||
|
|
||||||
// FATAL level logging
|
|
||||||
FATAL uint8 = 16
|
|
||||||
|
|
||||||
// BYPASS level logging - does not use a log level
|
|
||||||
BYPASS uint8 = 255
|
|
||||||
)
|
|
||||||
|
|
||||||
var mapLogLevel = map[uint8]string{
|
|
||||||
TRACE: "TRACE | ",
|
|
||||||
DEBUG: "DEBUG | ",
|
|
||||||
INFO: "INFO | ",
|
|
||||||
WARNING: "WARN | ",
|
|
||||||
ERROR: "ERROR | ",
|
|
||||||
FATAL: "FATAL | ",
|
|
||||||
BYPASS: "",
|
|
||||||
}
|
|
||||||
@@ -1,202 +0,0 @@
|
|||||||
package logger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/matryer/is"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestByteBufferLogger(t *testing.T) {
|
|
||||||
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
// Create new byte buffer logger
|
|
||||||
var buf bytes.Buffer
|
|
||||||
|
|
||||||
myLogger := New(&buf)
|
|
||||||
myLogger.SetLogLevel(TRACE)
|
|
||||||
|
|
||||||
tests := map[uint8]string{
|
|
||||||
TRACE: "TRACE | I am a message!\n",
|
|
||||||
DEBUG: "DEBUG | I am a message!\n",
|
|
||||||
WARNING: "WARN | I am a message!\n",
|
|
||||||
INFO: "INFO | I am a message!\n",
|
|
||||||
ERROR: "ERROR | I am a message!\n",
|
|
||||||
}
|
|
||||||
|
|
||||||
methods := map[uint8]func(string, ...interface{}) error{
|
|
||||||
TRACE: myLogger.Trace,
|
|
||||||
DEBUG: myLogger.Debug,
|
|
||||||
WARNING: myLogger.Warning,
|
|
||||||
INFO: myLogger.Info,
|
|
||||||
ERROR: myLogger.Error,
|
|
||||||
}
|
|
||||||
|
|
||||||
for level, expected := range tests {
|
|
||||||
|
|
||||||
buf.Reset()
|
|
||||||
|
|
||||||
method := methods[level]
|
|
||||||
|
|
||||||
// Write message
|
|
||||||
err := method("I am a message!")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
actual := buf.String()
|
|
||||||
|
|
||||||
is.Equal(actual, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
func TestCustomLogger(t *testing.T) {
|
|
||||||
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
// Create new byte buffer logger
|
|
||||||
var buf bytes.Buffer
|
|
||||||
|
|
||||||
myLogger := New(&buf)
|
|
||||||
myLogger.SetLogLevel(TRACE)
|
|
||||||
customLogger := myLogger.CustomLogger("Test")
|
|
||||||
|
|
||||||
tests := map[uint8]string{
|
|
||||||
TRACE: "TRACE | Test | I am a message!\n",
|
|
||||||
DEBUG: "DEBUG | Test | I am a message!\n",
|
|
||||||
WARNING: "WARN | Test | I am a message!\n",
|
|
||||||
INFO: "INFO | Test | I am a message!\n",
|
|
||||||
ERROR: "ERROR | Test | I am a message!\n",
|
|
||||||
}
|
|
||||||
|
|
||||||
methods := map[uint8]func(string, ...interface{}) error{
|
|
||||||
TRACE: customLogger.Trace,
|
|
||||||
DEBUG: customLogger.Debug,
|
|
||||||
WARNING: customLogger.Warning,
|
|
||||||
INFO: customLogger.Info,
|
|
||||||
ERROR: customLogger.Error,
|
|
||||||
}
|
|
||||||
|
|
||||||
for level, expected := range tests {
|
|
||||||
|
|
||||||
buf.Reset()
|
|
||||||
|
|
||||||
method := methods[level]
|
|
||||||
|
|
||||||
// Write message
|
|
||||||
err := method("I am a message!")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
actual := buf.String()
|
|
||||||
|
|
||||||
is.Equal(actual, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
func TestWriteln(t *testing.T) {
|
|
||||||
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
// Create new byte buffer logger
|
|
||||||
var buf bytes.Buffer
|
|
||||||
|
|
||||||
myLogger := New(&buf)
|
|
||||||
myLogger.SetLogLevel(DEBUG)
|
|
||||||
|
|
||||||
buf.Reset()
|
|
||||||
|
|
||||||
// Write message
|
|
||||||
err := myLogger.Writeln("I am a message!")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
actual := buf.String()
|
|
||||||
|
|
||||||
is.Equal(actual, "I am a message!\n")
|
|
||||||
|
|
||||||
buf.Reset()
|
|
||||||
|
|
||||||
// Write message
|
|
||||||
err = myLogger.Write("I am a message!")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
actual = buf.String()
|
|
||||||
|
|
||||||
is.Equal(actual, "I am a message!")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLogLevel(t *testing.T) {
|
|
||||||
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
// Create new byte buffer logger
|
|
||||||
var buf bytes.Buffer
|
|
||||||
|
|
||||||
myLogger := New(&buf)
|
|
||||||
myLogger.SetLogLevel(ERROR)
|
|
||||||
|
|
||||||
tests := map[uint8]string{
|
|
||||||
TRACE: "",
|
|
||||||
DEBUG: "",
|
|
||||||
WARNING: "",
|
|
||||||
INFO: "",
|
|
||||||
ERROR: "ERROR | I am a message!\n",
|
|
||||||
}
|
|
||||||
|
|
||||||
methods := map[uint8]func(string, ...interface{}) error{
|
|
||||||
TRACE: myLogger.Trace,
|
|
||||||
DEBUG: myLogger.Debug,
|
|
||||||
WARNING: myLogger.Warning,
|
|
||||||
INFO: myLogger.Info,
|
|
||||||
ERROR: myLogger.Error,
|
|
||||||
}
|
|
||||||
|
|
||||||
for level := range tests {
|
|
||||||
|
|
||||||
method := methods[level]
|
|
||||||
|
|
||||||
// Write message
|
|
||||||
err := method("I am a message!")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
actual := buf.String()
|
|
||||||
|
|
||||||
is.Equal(actual, "ERROR | I am a message!\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileLogger(t *testing.T) {
|
|
||||||
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
// Create new byte buffer logger
|
|
||||||
file, err := ioutil.TempFile(".", "wailsv2test")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.Remove(file.Name())
|
|
||||||
|
|
||||||
myLogger := New(file)
|
|
||||||
myLogger.SetLogLevel(DEBUG)
|
|
||||||
|
|
||||||
// Write message
|
|
||||||
err = myLogger.Info("I am a message!")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
actual, err := ioutil.ReadFile(file.Name())
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
is.Equal(string(actual), "INFO | I am a message!\n")
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client defines what a frontend client can do
|
// Client defines what a frontend client can do
|
||||||
@@ -13,9 +14,8 @@ type Client interface {
|
|||||||
Quit()
|
Quit()
|
||||||
NotifyEvent(message string)
|
NotifyEvent(message string)
|
||||||
CallResult(message string)
|
CallResult(message string)
|
||||||
SaveFileDialog(title string, filter string) string
|
OpenDialog(dialogOptions *options.OpenDialog, callbackID string)
|
||||||
OpenFileDialog(title string, filter string) string
|
SaveDialog(dialogOptions *options.SaveDialog, callbackID string)
|
||||||
OpenDirectoryDialog(title string, filter string) string
|
|
||||||
WindowSetTitle(title string)
|
WindowSetTitle(title string)
|
||||||
WindowShow()
|
WindowShow()
|
||||||
WindowHide()
|
WindowHide()
|
||||||
@@ -28,7 +28,8 @@ type Client interface {
|
|||||||
WindowSize(width int, height int)
|
WindowSize(width int, height int)
|
||||||
WindowFullscreen()
|
WindowFullscreen()
|
||||||
WindowUnFullscreen()
|
WindowUnFullscreen()
|
||||||
WindowSetColour(colour string) bool
|
WindowSetColour(colour int)
|
||||||
|
DarkModeEnabled(callbackID string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DispatchClient is what the frontends use to interface with the
|
// DispatchClient is what the frontends use to interface with the
|
||||||
@@ -63,7 +64,7 @@ func (d *DispatchClient) DispatchMessage(incomingMessage string) {
|
|||||||
d.logger.Trace(fmt.Sprintf("Received message: %+v", incomingMessage))
|
d.logger.Trace(fmt.Sprintf("Received message: %+v", incomingMessage))
|
||||||
parsedMessage, err := message.Parse(incomingMessage)
|
parsedMessage, err := message.Parse(incomingMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Trace("Error: " + err.Error())
|
d.logger.Error(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +75,7 @@ func (d *DispatchClient) DispatchMessage(incomingMessage string) {
|
|||||||
|
|
||||||
// Check error
|
// Check error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Trace("Error: " + err.Error())
|
d.logger.Error(err.Error())
|
||||||
// Hrm... what do we do with this?
|
// Hrm... what do we do with this?
|
||||||
d.bus.PublishForTarget("generic:message", incomingMessage, d.id)
|
d.bus.PublishForTarget("generic:message", incomingMessage, d.id)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type CallMessage struct {
|
type CallMessage struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Args []interface{} `json:"args"`
|
Args []json.RawMessage `json:"args"`
|
||||||
CallbackID string `json:"callbackID,omitempty"`
|
CallbackID string `json:"callbackID,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// callMessageParser does what it says on the tin!
|
// callMessageParser does what it says on the tin!
|
||||||
@@ -22,6 +22,7 @@ func callMessageParser(message string) (*parsedMessage, error) {
|
|||||||
callMessage := new(CallMessage)
|
callMessage := new(CallMessage)
|
||||||
|
|
||||||
m := message[1:]
|
m := message[1:]
|
||||||
|
|
||||||
err := json.Unmarshal([]byte(m), callMessage)
|
err := json.Unmarshal([]byte(m), callMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(err.Error())
|
println(err.Error())
|
||||||
|
|||||||
52
v2/internal/messagedispatcher/message/dialog.go
Normal file
52
v2/internal/messagedispatcher/message/dialog.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package message
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// dialogMessageParser does what it says on the tin!
|
||||||
|
func dialogMessageParser(message string) (*parsedMessage, error) {
|
||||||
|
|
||||||
|
// Sanity check: Dialog messages must be at least 4 bytes
|
||||||
|
if len(message) < 4 {
|
||||||
|
return nil, fmt.Errorf("dialog message was an invalid length")
|
||||||
|
}
|
||||||
|
|
||||||
|
var topic = "bad topic from dialogMessageParser"
|
||||||
|
var responseMessage *parsedMessage
|
||||||
|
|
||||||
|
// Switch the event type (with or without data)
|
||||||
|
switch message[0] {
|
||||||
|
// Format of Dialog response messages: D<dialog type><callbackID>|<[]string as json encoded string>
|
||||||
|
case 'D':
|
||||||
|
dialogType := message[1]
|
||||||
|
message = message[2:]
|
||||||
|
idx := strings.IndexByte(message, '|')
|
||||||
|
if idx < 0 {
|
||||||
|
return nil, fmt.Errorf("Invalid dialog response message format")
|
||||||
|
}
|
||||||
|
callbackID := message[:idx+1]
|
||||||
|
payloadData := message[idx+1:]
|
||||||
|
|
||||||
|
switch dialogType {
|
||||||
|
case 'O':
|
||||||
|
var data []string
|
||||||
|
topic = "dialog:openselected:" + callbackID
|
||||||
|
err := json.Unmarshal([]byte(payloadData), &data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
responseMessage = &parsedMessage{Topic: topic, Data: data}
|
||||||
|
case 'S':
|
||||||
|
topic = "dialog:saveselected:" + callbackID
|
||||||
|
responseMessage = &parsedMessage{Topic: topic, Data: payloadData}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Invalid message to dialogMessageParser()")
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseMessage, nil
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package message
|
package message
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"encoding/json"
|
||||||
import "encoding/json"
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
type EventMessage struct {
|
type EventMessage struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@@ -12,6 +13,7 @@ type EventMessage struct {
|
|||||||
type OnEventMessage struct {
|
type OnEventMessage struct {
|
||||||
Name string
|
Name string
|
||||||
Callback func(optionalData ...interface{})
|
Callback func(optionalData ...interface{})
|
||||||
|
Counter int
|
||||||
}
|
}
|
||||||
|
|
||||||
// eventMessageParser does what it says on the tin!
|
// eventMessageParser does what it says on the tin!
|
||||||
@@ -27,8 +29,6 @@ func eventMessageParser(message string) (*parsedMessage, error) {
|
|||||||
|
|
||||||
// Switch the event type (with or without data)
|
// Switch the event type (with or without data)
|
||||||
switch message[0] {
|
switch message[0] {
|
||||||
case 'e':
|
|
||||||
eventMessage.Name = message[2:]
|
|
||||||
case 'E':
|
case 'E':
|
||||||
m := message[2:]
|
m := message[2:]
|
||||||
err := json.Unmarshal([]byte(m), eventMessage)
|
err := json.Unmarshal([]byte(m), eventMessage)
|
||||||
|
|||||||
@@ -3,11 +3,14 @@ package message
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
var logMessageMap = map[byte]string{
|
var logMessageMap = map[byte]string{
|
||||||
|
'P': "log:print",
|
||||||
|
'T': "log:trace",
|
||||||
'D': "log:debug",
|
'D': "log:debug",
|
||||||
'I': "log:info",
|
'I': "log:info",
|
||||||
'W': "log:warning",
|
'W': "log:warning",
|
||||||
'E': "log:error",
|
'E': "log:error",
|
||||||
'F': "log:fatal",
|
'F': "log:fatal",
|
||||||
|
'S': "log:setlevel",
|
||||||
}
|
}
|
||||||
|
|
||||||
// logMessageParser does what it says on the tin!
|
// logMessageParser does what it says on the tin!
|
||||||
@@ -23,7 +26,7 @@ func logMessageParser(message string) (*parsedMessage, error) {
|
|||||||
|
|
||||||
// If the type is invalid, raise error
|
// If the type is invalid, raise error
|
||||||
if messageTopic == "" {
|
if messageTopic == "" {
|
||||||
return nil, fmt.Errorf("log message type '%b' invalid", message[1])
|
return nil, fmt.Errorf("log message type '%c' invalid", message[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new parsed message struct
|
// Create a new parsed message struct
|
||||||
|
|||||||
@@ -14,9 +14,10 @@ var messageParsers = map[byte]func(string) (*parsedMessage, error){
|
|||||||
'L': logMessageParser,
|
'L': logMessageParser,
|
||||||
'R': runtimeMessageParser,
|
'R': runtimeMessageParser,
|
||||||
'E': eventMessageParser,
|
'E': eventMessageParser,
|
||||||
'e': eventMessageParser,
|
|
||||||
'C': callMessageParser,
|
'C': callMessageParser,
|
||||||
'W': windowMessageParser,
|
'W': windowMessageParser,
|
||||||
|
'D': dialogMessageParser,
|
||||||
|
'S': systemMessageParser,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse will attempt to parse the given message
|
// Parse will attempt to parse the given message
|
||||||
|
|||||||
@@ -22,13 +22,14 @@ func runtimeMessageParser(message string) (*parsedMessage, error) {
|
|||||||
|
|
||||||
// processBrowserMessage expects messages of the following format:
|
// processBrowserMessage expects messages of the following format:
|
||||||
// RB<METHOD><DATA>
|
// RB<METHOD><DATA>
|
||||||
|
// O = Open
|
||||||
func processBrowserMessage(message string) (*parsedMessage, error) {
|
func processBrowserMessage(message string) (*parsedMessage, error) {
|
||||||
method := message[2]
|
method := message[2]
|
||||||
switch method {
|
switch method {
|
||||||
case 'U':
|
case 'O':
|
||||||
// Open URL
|
// Open URL
|
||||||
url := message[3:]
|
target := message[3:]
|
||||||
return &parsedMessage{Topic: "runtime:browser:openurl", Data: url}, nil
|
return &parsedMessage{Topic: "runtime:browser:open", Data: target}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("unknown browser message: %s", message)
|
return nil, fmt.Errorf("unknown browser message: %s", message)
|
||||||
|
|||||||
42
v2/internal/messagedispatcher/message/system.go
Normal file
42
v2/internal/messagedispatcher/message/system.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package message
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// systemMessageParser does what it says on the tin!
|
||||||
|
func systemMessageParser(message string) (*parsedMessage, error) {
|
||||||
|
|
||||||
|
// Sanity check: system messages must be at least 4 bytes
|
||||||
|
if len(message) < 4 {
|
||||||
|
return nil, fmt.Errorf("system message was an invalid length")
|
||||||
|
}
|
||||||
|
|
||||||
|
var responseMessage *parsedMessage
|
||||||
|
|
||||||
|
// Remove 'S'
|
||||||
|
message = message[1:]
|
||||||
|
|
||||||
|
// Switch the event type (with or without data)
|
||||||
|
switch message[0] {
|
||||||
|
// Format of system response messages: S<command><callbackID>|<payload>
|
||||||
|
// DarkModeEnabled
|
||||||
|
case 'D':
|
||||||
|
message = message[1:]
|
||||||
|
idx := strings.IndexByte(message, '|')
|
||||||
|
if idx < 0 {
|
||||||
|
return nil, fmt.Errorf("Invalid system response message format")
|
||||||
|
}
|
||||||
|
callbackID := message[:idx]
|
||||||
|
payloadData := message[idx+1:]
|
||||||
|
|
||||||
|
topic := "systemresponse:" + callbackID
|
||||||
|
responseMessage = &parsedMessage{Topic: topic, Data: payloadData == "T"}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Invalid message to systemMessageParser()")
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseMessage, nil
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Dispatcher translates messages received from the frontend
|
// Dispatcher translates messages received from the frontend
|
||||||
@@ -20,6 +21,7 @@ type Dispatcher struct {
|
|||||||
eventChannel <-chan *servicebus.Message
|
eventChannel <-chan *servicebus.Message
|
||||||
windowChannel <-chan *servicebus.Message
|
windowChannel <-chan *servicebus.Message
|
||||||
dialogChannel <-chan *servicebus.Message
|
dialogChannel <-chan *servicebus.Message
|
||||||
|
systemChannel <-chan *servicebus.Message
|
||||||
running bool
|
running bool
|
||||||
|
|
||||||
servicebus *servicebus.ServiceBus
|
servicebus *servicebus.ServiceBus
|
||||||
@@ -62,6 +64,11 @@ func New(servicebus *servicebus.ServiceBus, logger *logger.Logger) (*Dispatcher,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
systemChannel, err := servicebus.Subscribe("system:")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
result := &Dispatcher{
|
result := &Dispatcher{
|
||||||
servicebus: servicebus,
|
servicebus: servicebus,
|
||||||
eventChannel: eventChannel,
|
eventChannel: eventChannel,
|
||||||
@@ -71,6 +78,7 @@ func New(servicebus *servicebus.ServiceBus, logger *logger.Logger) (*Dispatcher,
|
|||||||
quitChannel: quitChannel,
|
quitChannel: quitChannel,
|
||||||
windowChannel: windowChannel,
|
windowChannel: windowChannel,
|
||||||
dialogChannel: dialogChannel,
|
dialogChannel: dialogChannel,
|
||||||
|
systemChannel: systemChannel,
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -98,6 +106,8 @@ func (d *Dispatcher) Start() error {
|
|||||||
d.processWindowMessage(windowMessage)
|
d.processWindowMessage(windowMessage)
|
||||||
case dialogMessage := <-d.dialogChannel:
|
case dialogMessage := <-d.dialogChannel:
|
||||||
d.processDialogMessage(dialogMessage)
|
d.processDialogMessage(dialogMessage)
|
||||||
|
case systemMessage := <-d.systemChannel:
|
||||||
|
d.processSystemMessage(systemMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,6 +183,28 @@ func (d *Dispatcher) processCallResult(result *servicebus.Message) {
|
|||||||
client.frontend.CallResult(result.Data().(string))
|
client.frontend.CallResult(result.Data().(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// processSystem
|
||||||
|
func (d *Dispatcher) processSystemMessage(result *servicebus.Message) {
|
||||||
|
|
||||||
|
d.logger.Trace("Got system in message dispatcher: %+v", result)
|
||||||
|
|
||||||
|
splitTopic := strings.Split(result.Topic(), ":")
|
||||||
|
command := splitTopic[1]
|
||||||
|
callbackID := splitTopic[2]
|
||||||
|
switch command {
|
||||||
|
case "isdarkmode":
|
||||||
|
d.lock.RLock()
|
||||||
|
for _, client := range d.clients {
|
||||||
|
client.frontend.DarkModeEnabled(callbackID)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
d.lock.RUnlock()
|
||||||
|
|
||||||
|
default:
|
||||||
|
d.logger.Error("Unknown system command: %s", command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// processEvent will
|
// processEvent will
|
||||||
func (d *Dispatcher) processEvent(result *servicebus.Message) {
|
func (d *Dispatcher) processEvent(result *servicebus.Message) {
|
||||||
|
|
||||||
@@ -231,7 +263,7 @@ func (d *Dispatcher) processWindowMessage(result *servicebus.Message) {
|
|||||||
client.frontend.WindowUnFullscreen()
|
client.frontend.WindowUnFullscreen()
|
||||||
}
|
}
|
||||||
case "setcolour":
|
case "setcolour":
|
||||||
colour, ok := result.Data().(string)
|
colour, ok := result.Data().(int)
|
||||||
if !ok {
|
if !ok {
|
||||||
d.logger.Error("Invalid colour for 'window:setcolour' : %#v", result.Data())
|
d.logger.Error("Invalid colour for 'window:setcolour' : %#v", result.Data())
|
||||||
return
|
return
|
||||||
@@ -317,7 +349,6 @@ func (d *Dispatcher) processWindowMessage(result *servicebus.Message) {
|
|||||||
// processDialogMessage processes dialog messages
|
// processDialogMessage processes dialog messages
|
||||||
func (d *Dispatcher) processDialogMessage(result *servicebus.Message) {
|
func (d *Dispatcher) processDialogMessage(result *servicebus.Message) {
|
||||||
splitTopic := strings.Split(result.Topic(), ":")
|
splitTopic := strings.Split(result.Topic(), ":")
|
||||||
|
|
||||||
if len(splitTopic) < 4 {
|
if len(splitTopic) < 4 {
|
||||||
d.logger.Error("Invalid dialog message : %#v", result.Data())
|
d.logger.Error("Invalid dialog message : %#v", result.Data())
|
||||||
return
|
return
|
||||||
@@ -327,65 +358,42 @@ func (d *Dispatcher) processDialogMessage(result *servicebus.Message) {
|
|||||||
switch command {
|
switch command {
|
||||||
case "select":
|
case "select":
|
||||||
dialogType := splitTopic[2]
|
dialogType := splitTopic[2]
|
||||||
title := splitTopic[3]
|
|
||||||
filter := ""
|
|
||||||
if len(splitTopic) > 4 {
|
|
||||||
filter = splitTopic[4]
|
|
||||||
}
|
|
||||||
switch dialogType {
|
switch dialogType {
|
||||||
case "file":
|
case "open":
|
||||||
responseTopic, ok := result.Data().(string)
|
dialogOptions, ok := result.Data().(*options.OpenDialog)
|
||||||
if !ok {
|
if !ok {
|
||||||
d.logger.Error("Invalid responseTopic for 'dialog:select:file' : %#v", result.Data())
|
d.logger.Error("Invalid data for 'dialog:select:open' : %#v", result.Data())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
d.logger.Info("Opening File dialog! responseTopic = %s", responseTopic)
|
// This is hardcoded in the sender too
|
||||||
|
callbackID := splitTopic[3]
|
||||||
|
|
||||||
// TODO: Work out what we mean in a multi window environment...
|
// TODO: Work out what we mean in a multi window environment...
|
||||||
// For now we will just pick the first one
|
// For now we will just pick the first one
|
||||||
var result string
|
|
||||||
for _, client := range d.clients {
|
for _, client := range d.clients {
|
||||||
result = client.frontend.OpenFileDialog(title, filter)
|
client.frontend.OpenDialog(dialogOptions, callbackID)
|
||||||
}
|
}
|
||||||
|
case "save":
|
||||||
// Send dummy response
|
dialogOptions, ok := result.Data().(*options.SaveDialog)
|
||||||
d.servicebus.Publish(responseTopic, result)
|
|
||||||
case "filesave":
|
|
||||||
responseTopic, ok := result.Data().(string)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
d.logger.Error("Invalid responseTopic for 'dialog:select:filesave' : %#v", result.Data())
|
d.logger.Error("Invalid data for 'dialog:select:save' : %#v", result.Data())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
d.logger.Info("Opening Save File dialog! responseTopic = %s", responseTopic)
|
// This is hardcoded in the sender too
|
||||||
|
callbackID := splitTopic[3]
|
||||||
|
|
||||||
// TODO: Work out what we mean in a multi window environment...
|
// TODO: Work out what we mean in a multi window environment...
|
||||||
// For now we will just pick the first one
|
// For now we will just pick the first one
|
||||||
var result string
|
|
||||||
for _, client := range d.clients {
|
for _, client := range d.clients {
|
||||||
result = client.frontend.SaveFileDialog(title, filter)
|
client.frontend.SaveDialog(dialogOptions, callbackID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send dummy response
|
|
||||||
d.servicebus.Publish(responseTopic, result)
|
|
||||||
case "directory":
|
|
||||||
responseTopic, ok := result.Data().(string)
|
|
||||||
if !ok {
|
|
||||||
d.logger.Error("Invalid responseTopic for 'dialog:select:directory' : %#v", result.Data())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
d.logger.Info("Opening Directory dialog! responseTopic = %s", responseTopic)
|
|
||||||
|
|
||||||
// TODO: Work out what we mean in a multi window environment...
|
|
||||||
// For now we will just pick the first one
|
|
||||||
var result string
|
|
||||||
for _, client := range d.clients {
|
|
||||||
result = client.frontend.OpenDirectoryDialog(title, filter)
|
|
||||||
}
|
|
||||||
// Send dummy response
|
|
||||||
d.servicebus.Publish(responseTopic, result)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
d.logger.Error("Unknown dialog command: %s", command)
|
d.logger.Error("Unknown dialog type: %s", dialogType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
d.logger.Error("Unknown dialog command: %s", command)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ func ParseProject(projectPath string) (BoundStructs, error) {
|
|||||||
var wailsPkgVar = ""
|
var wailsPkgVar = ""
|
||||||
|
|
||||||
ast.Inspect(file, func(n ast.Node) bool {
|
ast.Inspect(file, func(n ast.Node) bool {
|
||||||
var s string
|
|
||||||
switch x := n.(type) {
|
switch x := n.(type) {
|
||||||
// Parse import declarations
|
// Parse import declarations
|
||||||
case *ast.ImportSpec:
|
case *ast.ImportSpec:
|
||||||
|
|||||||
@@ -3,19 +3,19 @@ package process
|
|||||||
import (
|
import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Process defines a process that can be executed
|
// Process defines a process that can be executed
|
||||||
type Process struct {
|
type Process struct {
|
||||||
logger *logger.Logger
|
logger *clilogger.CLILogger
|
||||||
cmd *exec.Cmd
|
cmd *exec.Cmd
|
||||||
exitChannel chan bool
|
exitChannel chan bool
|
||||||
Running bool
|
Running bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProcess creates a new process struct
|
// NewProcess creates a new process struct
|
||||||
func NewProcess(logger *logger.Logger, cmd string, args ...string) *Process {
|
func NewProcess(logger *clilogger.CLILogger, cmd string, args ...string) *Process {
|
||||||
return &Process{
|
return &Process{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
cmd: exec.Command(cmd, args...),
|
cmd: exec.Command(cmd, args...),
|
||||||
@@ -33,10 +33,10 @@ func (p *Process) Start() error {
|
|||||||
|
|
||||||
p.Running = true
|
p.Running = true
|
||||||
|
|
||||||
go func(cmd *exec.Cmd, running *bool, logger *logger.Logger, exitChannel chan bool) {
|
go func(cmd *exec.Cmd, running *bool, logger *clilogger.CLILogger, exitChannel chan bool) {
|
||||||
logger.Info("Starting process (PID: %d)", cmd.Process.Pid)
|
logger.Println("Starting process (PID: %d)", cmd.Process.Pid)
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
logger.Info("Exiting process (PID: %d)", cmd.Process.Pid)
|
logger.Println("Exiting process (PID: %d)", cmd.Process.Pid)
|
||||||
*running = false
|
*running = false
|
||||||
exitChannel <- true
|
exitChannel <- true
|
||||||
}(p.cmd, &p.Running, p.logger, p.exitChannel)
|
}(p.cmd, &p.Running, p.logger, p.exitChannel)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package goruntime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -8,23 +8,23 @@ import (
|
|||||||
|
|
||||||
// Browser defines all browser related operations
|
// Browser defines all browser related operations
|
||||||
type Browser interface {
|
type Browser interface {
|
||||||
Open(url string) error
|
Open(target string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type browser struct{}
|
type browser struct{}
|
||||||
|
|
||||||
// Open a url / file using the system default application
|
// Open a url / file using the system default application
|
||||||
// Credit: https://gist.github.com/hyg/9c4afcd91fe24316cbf0
|
// Credit: https://gist.github.com/hyg/9c4afcd91fe24316cbf0
|
||||||
func (b *browser) Open(url string) error {
|
func (b *browser) Open(target string) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "linux":
|
case "linux":
|
||||||
err = exec.Command("xdg-open", url).Start()
|
err = exec.Command("xdg-open", target).Start()
|
||||||
case "windows":
|
case "windows":
|
||||||
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
|
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", target).Start()
|
||||||
case "darwin":
|
case "darwin":
|
||||||
err = exec.Command("open", url).Start()
|
err = exec.Command("open", target).Start()
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("unsupported platform")
|
err = fmt.Errorf("unsupported platform")
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package goruntime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
94
v2/internal/runtime/dialog.go
Normal file
94
v2/internal/runtime/dialog.go
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/internal/crypto"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Dialog defines all Dialog related operations
|
||||||
|
type Dialog interface {
|
||||||
|
Open(dialogOptions *options.OpenDialog) []string
|
||||||
|
Save(dialogOptions *options.SaveDialog) string
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialog exposes the Dialog interface
|
||||||
|
type dialog struct {
|
||||||
|
bus *servicebus.ServiceBus
|
||||||
|
}
|
||||||
|
|
||||||
|
// newDialogs creates a new Dialogs struct
|
||||||
|
func newDialog(bus *servicebus.ServiceBus) Dialog {
|
||||||
|
return &dialog{
|
||||||
|
bus: bus,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// processTitleAndFilter return the title and filter from the given params.
|
||||||
|
// title is the first string, filter is the second
|
||||||
|
func (r *dialog) processTitleAndFilter(params ...string) (string, string) {
|
||||||
|
|
||||||
|
var title, filter string
|
||||||
|
|
||||||
|
if len(params) > 0 {
|
||||||
|
title = params[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(params) > 1 {
|
||||||
|
filter = params[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return title, filter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open prompts the user to select a file
|
||||||
|
func (r *dialog) Open(dialogOptions *options.OpenDialog) []string {
|
||||||
|
|
||||||
|
// Create unique dialog callback
|
||||||
|
uniqueCallback := crypto.RandomID()
|
||||||
|
|
||||||
|
// Subscribe to the respose channel
|
||||||
|
responseTopic := "dialog:openselected:" + uniqueCallback
|
||||||
|
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
message := "dialog:select:open:" + uniqueCallback
|
||||||
|
r.bus.Publish(message, dialogOptions)
|
||||||
|
|
||||||
|
// Wait for result
|
||||||
|
var result *servicebus.Message = <-dialogResponseChannel
|
||||||
|
|
||||||
|
// Delete subscription to response topic
|
||||||
|
r.bus.UnSubscribe(responseTopic)
|
||||||
|
|
||||||
|
return result.Data().([]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save prompts the user to select a file
|
||||||
|
func (r *dialog) Save(dialogOptions *options.SaveDialog) string {
|
||||||
|
|
||||||
|
// Create unique dialog callback
|
||||||
|
uniqueCallback := crypto.RandomID()
|
||||||
|
|
||||||
|
// Subscribe to the respose channel
|
||||||
|
responseTopic := "dialog:saveselected:" + uniqueCallback
|
||||||
|
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
message := "dialog:select:save:" + uniqueCallback
|
||||||
|
r.bus.Publish(message, dialogOptions)
|
||||||
|
|
||||||
|
// Wait for result
|
||||||
|
var result *servicebus.Message = <-dialogResponseChannel
|
||||||
|
|
||||||
|
// Delete subscription to response topic
|
||||||
|
r.bus.UnSubscribe(responseTopic)
|
||||||
|
|
||||||
|
return result.Data().(string)
|
||||||
|
}
|
||||||
68
v2/internal/runtime/events.go
Normal file
68
v2/internal/runtime/events.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Events defines all events related operations
|
||||||
|
type Events interface {
|
||||||
|
On(eventName string, callback func(optionalData ...interface{}))
|
||||||
|
Once(eventName string, callback func(optionalData ...interface{}))
|
||||||
|
OnMultiple(eventName string, callback func(optionalData ...interface{}), maxCallbacks int)
|
||||||
|
Emit(eventName string, optionalData ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// event exposes the events interface
|
||||||
|
type event struct {
|
||||||
|
bus *servicebus.ServiceBus
|
||||||
|
}
|
||||||
|
|
||||||
|
// newEvents creates a new Events struct
|
||||||
|
func newEvents(bus *servicebus.ServiceBus) Events {
|
||||||
|
return &event{
|
||||||
|
bus: bus,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// On registers a listener for a particular event
|
||||||
|
func (r *event) On(eventName string, callback func(optionalData ...interface{})) {
|
||||||
|
eventMessage := &message.OnEventMessage{
|
||||||
|
Name: eventName,
|
||||||
|
Callback: callback,
|
||||||
|
Counter: -1,
|
||||||
|
}
|
||||||
|
r.bus.Publish("event:on", eventMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once registers a listener for a particular event. After the first callback, the
|
||||||
|
// listener is deleted.
|
||||||
|
func (r *event) Once(eventName string, callback func(optionalData ...interface{})) {
|
||||||
|
eventMessage := &message.OnEventMessage{
|
||||||
|
Name: eventName,
|
||||||
|
Callback: callback,
|
||||||
|
Counter: 1,
|
||||||
|
}
|
||||||
|
r.bus.Publish("event:on", eventMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnMultiple registers a listener for a particular event, for a given maximum amount of callbacks.
|
||||||
|
// Once the callback has been run `maxCallbacks` times, the listener is deleted.
|
||||||
|
func (r *event) OnMultiple(eventName string, callback func(optionalData ...interface{}), maxCallbacks int) {
|
||||||
|
eventMessage := &message.OnEventMessage{
|
||||||
|
Name: eventName,
|
||||||
|
Callback: callback,
|
||||||
|
Counter: maxCallbacks,
|
||||||
|
}
|
||||||
|
r.bus.Publish("event:on", eventMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit pass through
|
||||||
|
func (r *event) Emit(eventName string, optionalData ...interface{}) {
|
||||||
|
eventMessage := &message.EventMessage{
|
||||||
|
Name: eventName,
|
||||||
|
Data: optionalData,
|
||||||
|
}
|
||||||
|
|
||||||
|
r.bus.Publish("event:emit:from:g", eventMessage)
|
||||||
|
}
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
package goruntime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/crypto"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Dialog defines all Dialog related operations
|
|
||||||
type Dialog interface {
|
|
||||||
SaveFile(params ...string) string
|
|
||||||
SelectFile(params ...string) string
|
|
||||||
SelectDirectory(params ...string) string
|
|
||||||
}
|
|
||||||
|
|
||||||
// dialog exposes the Dialog interface
|
|
||||||
type dialog struct {
|
|
||||||
bus *servicebus.ServiceBus
|
|
||||||
}
|
|
||||||
|
|
||||||
// newDialogs creates a new Dialogs struct
|
|
||||||
func newDialog(bus *servicebus.ServiceBus) Dialog {
|
|
||||||
return &dialog{
|
|
||||||
bus: bus,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// processTitleAndFilter return the title and filter from the given params.
|
|
||||||
// title is the first string, filter is the second
|
|
||||||
func (r *dialog) processTitleAndFilter(params ...string) (string, string) {
|
|
||||||
|
|
||||||
var title, filter string
|
|
||||||
|
|
||||||
if len(params) > 0 {
|
|
||||||
title = params[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(params) > 1 {
|
|
||||||
filter = params[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return title, filter
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectFile prompts the user to select a file
|
|
||||||
func (r *dialog) SelectFile(params ...string) string {
|
|
||||||
|
|
||||||
// Extract title + filter
|
|
||||||
title, filter := r.processTitleAndFilter(params...)
|
|
||||||
|
|
||||||
// Create unique dialog callback
|
|
||||||
uniqueCallback := crypto.RandomID()
|
|
||||||
|
|
||||||
// Subscribe to the respose channel
|
|
||||||
responseTopic := "dialog:fileselected:" + uniqueCallback
|
|
||||||
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Publish dialog request
|
|
||||||
message := "dialog:select:file:" + title
|
|
||||||
if filter != "" {
|
|
||||||
message += ":" + filter
|
|
||||||
}
|
|
||||||
r.bus.Publish(message, responseTopic)
|
|
||||||
|
|
||||||
// Wait for result
|
|
||||||
result := <-dialogResponseChannel
|
|
||||||
|
|
||||||
// Delete subscription to response topic
|
|
||||||
r.bus.UnSubscribe(responseTopic)
|
|
||||||
|
|
||||||
return result.Data().(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveFile prompts the user to select a file to save to
|
|
||||||
func (r *dialog) SaveFile(params ...string) string {
|
|
||||||
|
|
||||||
// Extract title + filter
|
|
||||||
title, filter := r.processTitleAndFilter(params...)
|
|
||||||
|
|
||||||
// Create unique dialog callback
|
|
||||||
uniqueCallback := crypto.RandomID()
|
|
||||||
|
|
||||||
// Subscribe to the respose channel
|
|
||||||
responseTopic := "dialog:filesaveselected:" + uniqueCallback
|
|
||||||
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Publish dialog request
|
|
||||||
message := "dialog:select:filesave:" + title
|
|
||||||
if filter != "" {
|
|
||||||
message += ":" + filter
|
|
||||||
}
|
|
||||||
r.bus.Publish(message, responseTopic)
|
|
||||||
|
|
||||||
// Wait for result
|
|
||||||
result := <-dialogResponseChannel
|
|
||||||
|
|
||||||
// Delete subscription to response topic
|
|
||||||
r.bus.UnSubscribe(responseTopic)
|
|
||||||
|
|
||||||
return result.Data().(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectDirectory prompts the user to select a file
|
|
||||||
func (r *dialog) SelectDirectory(params ...string) string {
|
|
||||||
|
|
||||||
// Extract title + filter
|
|
||||||
title, filter := r.processTitleAndFilter(params...)
|
|
||||||
|
|
||||||
// Create unique dialog callback
|
|
||||||
uniqueCallback := crypto.RandomID()
|
|
||||||
|
|
||||||
// Subscribe to the respose channel
|
|
||||||
responseTopic := "dialog:directoryselected:" + uniqueCallback
|
|
||||||
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Publish dialog request
|
|
||||||
message := "dialog:select:directory:" + title
|
|
||||||
if filter != "" {
|
|
||||||
message += ":" + filter
|
|
||||||
}
|
|
||||||
r.bus.Publish(message, responseTopic)
|
|
||||||
|
|
||||||
// Wait for result
|
|
||||||
var result *servicebus.Message = <-dialogResponseChannel
|
|
||||||
|
|
||||||
// Delete subscription to response topic
|
|
||||||
r.bus.UnSubscribe(responseTopic)
|
|
||||||
|
|
||||||
return result.Data().(string)
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package goruntime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Events defines all events related operations
|
|
||||||
type Events interface {
|
|
||||||
On(eventName string, callback func(optionalData ...interface{}))
|
|
||||||
Emit(eventName string, optionalData ...interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// event exposes the events interface
|
|
||||||
type event struct {
|
|
||||||
bus *servicebus.ServiceBus
|
|
||||||
}
|
|
||||||
|
|
||||||
// newEvents creates a new Events struct
|
|
||||||
func newEvents(bus *servicebus.ServiceBus) Events {
|
|
||||||
return &event{
|
|
||||||
bus: bus,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// On pass through
|
|
||||||
func (r *event) On(eventName string, callback func(optionalData ...interface{})) {
|
|
||||||
eventMessage := &message.OnEventMessage{
|
|
||||||
Name: eventName,
|
|
||||||
Callback: callback,
|
|
||||||
}
|
|
||||||
r.bus.Publish("event:on", eventMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit pass through
|
|
||||||
func (r *event) Emit(eventName string, optionalData ...interface{}) {
|
|
||||||
eventMessage := &message.EventMessage{
|
|
||||||
Name: eventName,
|
|
||||||
Data: optionalData,
|
|
||||||
}
|
|
||||||
|
|
||||||
r.bus.Publish("event:emit:from:g", eventMessage)
|
|
||||||
}
|
|
||||||
@@ -12,23 +12,13 @@ The lightweight framework for web-like apps
|
|||||||
import { SendMessage } from 'ipc';
|
import { SendMessage } from 'ipc';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the given URL in the system browser
|
* Opens the given URL / filename in the system browser
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
* @param {string} url
|
* @param {string} target
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function OpenURL(url) {
|
export function Open(target) {
|
||||||
return SendMessage('RBU' + url);
|
return SendMessage('RBO' + target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the given filename using the system's default file handler
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @param {sting} filename
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function OpenFile(filename) {
|
|
||||||
return SendMessage('runtime:browser:openfile', filename);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -12,14 +12,16 @@ import { SetBindings } from './bindings';
|
|||||||
import { Init } from './main';
|
import { Init } from './main';
|
||||||
|
|
||||||
// Setup global error handler
|
// Setup global error handler
|
||||||
window.onerror = function (/*msg, url, lineNo, columnNo, error*/) {
|
window.onerror = function (msg, url, lineNo, columnNo, error) {
|
||||||
// window.wails.Log.Error('**** Caught Unhandled Error ****');
|
const errorMessage = {
|
||||||
// window.wails.Log.Error('Message: ' + msg);
|
message: msg,
|
||||||
// window.wails.Log.Error('URL: ' + url);
|
url: url,
|
||||||
// window.wails.Log.Error('Line No: ' + lineNo);
|
line: lineNo,
|
||||||
// window.wails.Log.Error('Column No: ' + columnNo);
|
column: columnNo,
|
||||||
// window.wails.Log.Error('error: ' + error);
|
error: JSON.stringify(error),
|
||||||
(function () { window.wails.Log.Error(new Error().stack); })();
|
stack: function() { return JSON.stringify(new Error().stack); }(),
|
||||||
|
};
|
||||||
|
window.wails.Log.Error(JSON.stringify(errorMessage));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialise the Runtime
|
// Initialise the Runtime
|
||||||
|
|||||||
23
v2/internal/runtime/js/core/dialog.js
Normal file
23
v2/internal/runtime/js/core/dialog.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
import { SendMessage } from 'ipc';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a dialog with the given parameters
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {object} options
|
||||||
|
*/
|
||||||
|
export function Open(options) {
|
||||||
|
SendMessage('DO'+JSON.stringify(options));
|
||||||
|
}
|
||||||
@@ -82,6 +82,38 @@ export function Once(eventName, callback) {
|
|||||||
OnMultiple(eventName, callback, 1);
|
OnMultiple(eventName, callback, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function notifyListeners(eventData) {
|
||||||
|
|
||||||
|
// Get the event name
|
||||||
|
var eventName = eventData.name;
|
||||||
|
|
||||||
|
// Check if we have any listeners for this event
|
||||||
|
if (eventListeners[eventName]) {
|
||||||
|
|
||||||
|
// Keep a list of listener indexes to destroy
|
||||||
|
const newEventListenerList = eventListeners[eventName].slice();
|
||||||
|
|
||||||
|
// Iterate listeners
|
||||||
|
for (let count = 0; count < eventListeners[eventName].length; count += 1) {
|
||||||
|
|
||||||
|
// Get next listener
|
||||||
|
const listener = eventListeners[eventName][count];
|
||||||
|
|
||||||
|
var data = eventData.data;
|
||||||
|
|
||||||
|
// Do the callback
|
||||||
|
const destroy = listener.Callback(data);
|
||||||
|
if (destroy) {
|
||||||
|
// if the listener indicated to destroy itself, add it to the destroy list
|
||||||
|
newEventListenerList.splice(count, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update callbacks with new list of listners
|
||||||
|
eventListeners[eventName] = newEventListenerList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify informs frontend listeners that an event was emitted with the given data
|
* Notify informs frontend listeners that an event was emitted with the given data
|
||||||
*
|
*
|
||||||
@@ -100,33 +132,7 @@ export function Notify(notifyMessage) {
|
|||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
var eventName = message.name;
|
notifyListeners(message);
|
||||||
|
|
||||||
// Check if we have any listeners for this event
|
|
||||||
if (eventListeners[eventName]) {
|
|
||||||
|
|
||||||
// Keep a list of listener indexes to destroy
|
|
||||||
const newEventListenerList = eventListeners[eventName].slice();
|
|
||||||
|
|
||||||
// Iterate listeners
|
|
||||||
for (let count = 0; count < eventListeners[eventName].length; count += 1) {
|
|
||||||
|
|
||||||
// Get next listener
|
|
||||||
const listener = eventListeners[eventName][count];
|
|
||||||
|
|
||||||
var data = message.data;
|
|
||||||
|
|
||||||
// Do the callback
|
|
||||||
const destroy = listener.Callback(data);
|
|
||||||
if (destroy) {
|
|
||||||
// if the listener indicated to destroy itself, add it to the destroy list
|
|
||||||
newEventListenerList.splice(count, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update callbacks with new list of listners
|
|
||||||
eventListeners[eventName] = newEventListenerList;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,66 +143,15 @@ export function Notify(notifyMessage) {
|
|||||||
*/
|
*/
|
||||||
export function Emit(eventName) {
|
export function Emit(eventName) {
|
||||||
|
|
||||||
// Calculate the data
|
const payload = {
|
||||||
if (arguments.length > 1) {
|
name: eventName,
|
||||||
// Notify backend
|
data: [].slice.apply(arguments).slice(1),
|
||||||
const payload = {
|
};
|
||||||
name: eventName,
|
|
||||||
data: [].slice.apply(arguments).slice(1),
|
// Notify JS listeners
|
||||||
};
|
notifyListeners(payload);
|
||||||
SendMessage('Ej' + JSON.stringify(payload));
|
|
||||||
} else {
|
// Notify Go listeners
|
||||||
SendMessage('ej' + eventName);
|
SendMessage('Ej' + JSON.stringify(payload));
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callbacks for the heartbeat calls
|
|
||||||
const heartbeatCallbacks = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Heartbeat emits the event `eventName`, every `timeInMilliseconds` milliseconds until
|
|
||||||
* the event is acknowledged via `Event.Acknowledge`. Once this happens, `callback` is invoked ONCE
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @param {string} eventName
|
|
||||||
* @param {number} timeInMilliseconds
|
|
||||||
* @param {function} callback
|
|
||||||
*/
|
|
||||||
export function Heartbeat(eventName, timeInMilliseconds, callback) {
|
|
||||||
|
|
||||||
// Declare interval variable
|
|
||||||
let interval = null;
|
|
||||||
|
|
||||||
// Setup callback
|
|
||||||
function dynamicCallback() {
|
|
||||||
// Kill interval
|
|
||||||
clearInterval(interval);
|
|
||||||
// Callback
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register callback
|
|
||||||
heartbeatCallbacks[eventName] = dynamicCallback;
|
|
||||||
|
|
||||||
// Start emitting the event
|
|
||||||
interval = setInterval(function () {
|
|
||||||
Emit(eventName);
|
|
||||||
}, timeInMilliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges a heartbeat event by name
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @param {string} eventName
|
|
||||||
*/
|
|
||||||
export function Acknowledge(eventName) {
|
|
||||||
// If we are waiting for acknowledgement for this event type
|
|
||||||
if (heartbeatCallbacks[eventName]) {
|
|
||||||
// Acknowledge!
|
|
||||||
heartbeatCallbacks[eventName]();
|
|
||||||
} else {
|
|
||||||
throw new Error(`Cannot acknowledge unknown heartbeat '${eventName}'`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -25,6 +25,26 @@ function sendLogMessage(level, message) {
|
|||||||
SendMessage('L' + level + message);
|
SendMessage('L' + level + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the given trace message with the backend
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
export function Trace(message) {
|
||||||
|
sendLogMessage('T', message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the given message with the backend
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
export function Print(message) {
|
||||||
|
sendLogMessage('P', message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log the given debug message with the backend
|
* Log the given debug message with the backend
|
||||||
*
|
*
|
||||||
@@ -74,3 +94,22 @@ export function Error(message) {
|
|||||||
export function Fatal(message) {
|
export function Fatal(message) {
|
||||||
sendLogMessage('F', message);
|
sendLogMessage('F', message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Log level to the given log level
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {number} loglevel
|
||||||
|
*/
|
||||||
|
export function SetLogLevel(loglevel) {
|
||||||
|
sendLogMessage('S', loglevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log levels
|
||||||
|
export const Level = {
|
||||||
|
TRACE: 1,
|
||||||
|
DEBUG: 2,
|
||||||
|
INFO: 3,
|
||||||
|
WARNING: 4,
|
||||||
|
ERROR: 5,
|
||||||
|
};
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ The lightweight framework for web-like apps
|
|||||||
import * as Log from './log';
|
import * as Log from './log';
|
||||||
import * as Browser from './browser';
|
import * as Browser from './browser';
|
||||||
import * as Window from './window';
|
import * as Window from './window';
|
||||||
import { On, OnMultiple, Emit, Notify, Heartbeat, Acknowledge } from './events';
|
import * as Dialog from './dialog';
|
||||||
import { Callback } from './calls';
|
import { On, Once, OnMultiple, Emit, Notify } from './events';
|
||||||
|
import { Callback, SystemCall } from './calls';
|
||||||
import { AddScript, InjectCSS } from './utils';
|
import { AddScript, InjectCSS } from './utils';
|
||||||
import { AddIPCListener } from 'ipc';
|
import { AddIPCListener } from 'ipc';
|
||||||
import * as Platform from 'platform';
|
import * as Platform from 'platform';
|
||||||
|
import * as Store from './store';
|
||||||
|
|
||||||
export function Init() {
|
export function Init() {
|
||||||
// Backend is where the Go struct wrappers get bound to
|
// Backend is where the Go struct wrappers get bound to
|
||||||
@@ -27,23 +29,35 @@ export function Init() {
|
|||||||
Log,
|
Log,
|
||||||
Browser,
|
Browser,
|
||||||
Window,
|
Window,
|
||||||
|
Dialog,
|
||||||
Events: {
|
Events: {
|
||||||
On,
|
On,
|
||||||
|
Once,
|
||||||
OnMultiple,
|
OnMultiple,
|
||||||
Emit,
|
Emit,
|
||||||
Heartbeat,
|
|
||||||
Acknowledge,
|
|
||||||
},
|
},
|
||||||
_: {
|
_: {
|
||||||
Callback,
|
Callback,
|
||||||
Notify,
|
Notify,
|
||||||
AddScript,
|
AddScript,
|
||||||
InjectCSS,
|
InjectCSS,
|
||||||
Init,
|
// Init,
|
||||||
AddIPCListener
|
AddIPCListener,
|
||||||
}
|
SystemCall,
|
||||||
|
},
|
||||||
|
Store,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Setup system. Store uses window.wails so needs to be setup after that
|
||||||
|
window.wails.System = {
|
||||||
|
IsDarkMode: Store.New('isdarkmode'),
|
||||||
|
LogLevel: Store.New('loglevel'),
|
||||||
|
};
|
||||||
|
// Copy platform specific information into it
|
||||||
|
Object.assign(window.wails.System, Platform.System);
|
||||||
|
|
||||||
// Do platform specific Init
|
// Do platform specific Init
|
||||||
Platform.Init();
|
Platform.Init();
|
||||||
|
|
||||||
|
window.wailsloader.runtime = true;
|
||||||
}
|
}
|
||||||
93
v2/internal/runtime/js/core/store.js
Normal file
93
v2/internal/runtime/js/core/store.js
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new sync store with the given name and optional default value
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} name
|
||||||
|
* @param {*} optionalDefault
|
||||||
|
*/
|
||||||
|
export function New(name, optionalDefault) {
|
||||||
|
|
||||||
|
// This is the store state
|
||||||
|
var state;
|
||||||
|
|
||||||
|
// Check we are initialised
|
||||||
|
if( !window.wails) {
|
||||||
|
throw Error('Wails is not initialised');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store for the callbacks
|
||||||
|
let callbacks = [];
|
||||||
|
|
||||||
|
// Subscribe to updates by providing a callback
|
||||||
|
let subscribe = function(callback) {
|
||||||
|
callbacks.push(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
// sets the store state to the provided `newstate` value
|
||||||
|
let set = function(newstate) {
|
||||||
|
|
||||||
|
state = newstate;
|
||||||
|
|
||||||
|
// Emit a notification to back end
|
||||||
|
window.wails.Events.Emit('wails:sync:store:updatedbyfrontend:'+name, JSON.stringify(state));
|
||||||
|
|
||||||
|
// Notify callbacks
|
||||||
|
callbacks.forEach( function(callback) {
|
||||||
|
callback(state);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// update mutates the value in the store by calling the
|
||||||
|
// provided method with the current value. The value returned
|
||||||
|
// by the updater function will be set as the new store value
|
||||||
|
let update = function(updater) {
|
||||||
|
var newValue = updater(state);
|
||||||
|
this.set(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
// get returns the current value of the store
|
||||||
|
let get = function() {
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setup event callback
|
||||||
|
window.wails.Events.On('wails:sync:store:updatedbybackend:'+name, function(jsonEncodedState) {
|
||||||
|
|
||||||
|
// Parse state
|
||||||
|
let newState = JSON.parse(jsonEncodedState);
|
||||||
|
|
||||||
|
// Todo: Potential preprocessing?
|
||||||
|
|
||||||
|
// Save state
|
||||||
|
state = newState;
|
||||||
|
|
||||||
|
// Notify callbacks
|
||||||
|
callbacks.forEach( function(callback) {
|
||||||
|
callback(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set to the optional default if set
|
||||||
|
if( optionalDefault ) {
|
||||||
|
this.set(optionalDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
get,
|
||||||
|
set,
|
||||||
|
update,
|
||||||
|
};
|
||||||
|
}
|
||||||
15
v2/internal/runtime/js/desktop/common.js
Normal file
15
v2/internal/runtime/js/desktop/common.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises platform specific code
|
||||||
|
*/
|
||||||
|
export const AppType = "desktop";
|
||||||
44
v2/internal/runtime/js/desktop/darwin.js
Normal file
44
v2/internal/runtime/js/desktop/darwin.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises platform specific code
|
||||||
|
*/
|
||||||
|
|
||||||
|
// import * as common from './common';
|
||||||
|
const common = require('./common');
|
||||||
|
|
||||||
|
export const System = {
|
||||||
|
...common,
|
||||||
|
Platform: () => "darwin",
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SendMessage(message) {
|
||||||
|
window.webkit.messageHandlers.external.postMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Init() {
|
||||||
|
|
||||||
|
// Setup drag handler
|
||||||
|
// Based on code from: https://github.com/patr0nus/DeskGap
|
||||||
|
window.addEventListener('mousedown', function (e) {
|
||||||
|
var currentElement = e.target;
|
||||||
|
while (currentElement != null) {
|
||||||
|
if (currentElement.hasAttribute('data-wails-no-drag')) {
|
||||||
|
break;
|
||||||
|
} else if (currentElement.hasAttribute('data-wails-drag')) {
|
||||||
|
window.webkit.messageHandlers.windowDrag.postMessage(null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
currentElement = currentElement.parentElement;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -14,8 +14,8 @@ The lightweight framework for web-like apps
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export const System = {
|
export const System = {
|
||||||
Platform: "linux",
|
...common,
|
||||||
AppType: "desktop"
|
Platform: () => "linux",
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SendMessage(message) {
|
export function SendMessage(message) {
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Wails Runtime
|
# Wails Runtime
|
||||||
|
|
||||||
This module is the Javascript runtime library for the [Wails](https://wails.app) framework. It is intended to be installed as part of a [Wails](https://wails.app) project, not a standalone module.
|
This module is the Javascript runtime library for the [Wails](https://wails.app) framework. It is intended to be installed as part of a [Wails](https://wails.app) V2 project, not a standalone module.
|
||||||
|
|||||||
@@ -10,28 +10,12 @@ The lightweight framework for web-like apps
|
|||||||
/* jshint esversion: 6 */
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the given URL in the system browser
|
* Opens the given URL or Filename in the system browser
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
* @param {string} url
|
* @param {string} target
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function OpenURL(url) {
|
export function Open(target) {
|
||||||
return window.wails.Browser.OpenURL(url);
|
return window.wails.Browser.Open(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the given filename using the system's default file handler
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @param {sting} filename
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function OpenFile(filename) {
|
|
||||||
return window.wails.Browser.OpenFile(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
OpenURL: OpenURL,
|
|
||||||
OpenFile: OpenFile
|
|
||||||
};
|
|
||||||
22
v2/internal/runtime/js/runtime/dialog.js
Normal file
22
v2/internal/runtime/js/runtime/dialog.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a dialog with the given parameters
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {object} options
|
||||||
|
*/
|
||||||
|
export function Open(options) {
|
||||||
|
window.wails.Dialog.Open(options);
|
||||||
|
}
|
||||||
@@ -56,35 +56,9 @@ function Emit(eventName) {
|
|||||||
return window.wails.Events.Emit.apply(null, args);
|
return window.wails.Events.Emit.apply(null, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Heartbeat emits the event `eventName`, every `timeInMilliseconds` milliseconds until
|
|
||||||
* the event is acknowledged via `Event.Acknowledge`. Once this happens, `callback` is invoked ONCE
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @param {string} eventName
|
|
||||||
* @param {number} timeInMilliseconds
|
|
||||||
* @param {function} callback
|
|
||||||
*/
|
|
||||||
function Heartbeat(eventName, timeInMilliseconds, callback) {
|
|
||||||
window.wails.Events.Heartbeat(eventName, timeInMilliseconds, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges a heartbeat event by name
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @param {string} eventName
|
|
||||||
*/
|
|
||||||
function Acknowledge(eventName) {
|
|
||||||
return window.wails.Events.Acknowledge(eventName);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
OnMultiple: OnMultiple,
|
OnMultiple: OnMultiple,
|
||||||
On: On,
|
On: On,
|
||||||
Once: Once,
|
Once: Once,
|
||||||
Emit: Emit,
|
Emit: Emit,
|
||||||
Heartbeat: Heartbeat,
|
|
||||||
Acknowledge: Acknowledge
|
|
||||||
};
|
};
|
||||||
@@ -11,6 +11,26 @@ The lightweight framework for web-like apps
|
|||||||
/* jshint esversion: 6 */
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the given message with the backend
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
function Print(message) {
|
||||||
|
window.wails.Log.Print(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the given trace message with the backend
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
function Trace(message) {
|
||||||
|
window.wails.Log.Trace(message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log the given debug message with the backend
|
* Log the given debug message with the backend
|
||||||
*
|
*
|
||||||
@@ -54,17 +74,40 @@ function Error(message) {
|
|||||||
/**
|
/**
|
||||||
* Log the given fatal message with the backend
|
* Log the given fatal message with the backend
|
||||||
*
|
*
|
||||||
* @export
|
|
||||||
* @param {string} message
|
* @param {string} message
|
||||||
*/
|
*/
|
||||||
function Fatal(message) {
|
function Fatal(message) {
|
||||||
window.wails.Log.Fatal(message);
|
window.wails.Log.Fatal(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Log level to the given log level
|
||||||
|
*
|
||||||
|
* @param {number} loglevel
|
||||||
|
*/
|
||||||
|
function SetLogLevel(loglevel) {
|
||||||
|
window.wails.Log.SetLogLevel(loglevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log levels
|
||||||
|
const Level = {
|
||||||
|
TRACE: 1,
|
||||||
|
DEBUG: 2,
|
||||||
|
INFO: 3,
|
||||||
|
WARNING: 4,
|
||||||
|
ERROR: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
Print: Print,
|
||||||
|
Trace: Trace,
|
||||||
Debug: Debug,
|
Debug: Debug,
|
||||||
Info: Info,
|
Info: Info,
|
||||||
Warning: Warning,
|
Warning: Warning,
|
||||||
Error: Error,
|
Error: Error,
|
||||||
Fatal: Fatal
|
Fatal: Fatal,
|
||||||
|
SetLogLevel: SetLogLevel,
|
||||||
|
Level: Level,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,12 +11,18 @@ The lightweight framework for web-like apps
|
|||||||
|
|
||||||
const Log = require('./log');
|
const Log = require('./log');
|
||||||
const Browser = require('./browser');
|
const Browser = require('./browser');
|
||||||
|
const Dialog = require('./dialog');
|
||||||
const Events = require('./events');
|
const Events = require('./events');
|
||||||
const Init = require('./init');
|
const Init = require('./init');
|
||||||
|
const System = require('./system');
|
||||||
|
const Store = require('./store');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Log: Log,
|
|
||||||
Browser: Browser,
|
Browser: Browser,
|
||||||
|
Dialog: Dialog,
|
||||||
Events: Events,
|
Events: Events,
|
||||||
Init: Init
|
Init: Init,
|
||||||
|
Log: Log,
|
||||||
|
System: System,
|
||||||
|
Store: Store,
|
||||||
};
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@wailsapp/runtime",
|
"name": "@wails/runtime",
|
||||||
"version": "1.0.10",
|
"version": "1.1.0",
|
||||||
"description": "Wails Javascript runtime library",
|
"description": "Wails V2 Javascript runtime library",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"types": "runtime.d.ts",
|
"types": "runtime.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
41
v2/internal/runtime/js/runtime/runtime.d.ts
vendored
41
v2/internal/runtime/js/runtime/runtime.d.ts
vendored
@@ -1,26 +1,49 @@
|
|||||||
export = wailsapp__runtime;
|
export = wailsapp__runtime;
|
||||||
|
|
||||||
|
interface Store {
|
||||||
|
get(): any;
|
||||||
|
set(value: any): void;
|
||||||
|
subscribe(callback: (newvalue: any) => void): void;
|
||||||
|
update(callback: (currentvalue: any) => any): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Level {
|
||||||
|
TRACE: 1,
|
||||||
|
DEBUG: 2,
|
||||||
|
INFO: 3,
|
||||||
|
WARNING: 4,
|
||||||
|
ERROR: 5,
|
||||||
|
};
|
||||||
|
|
||||||
declare const wailsapp__runtime: {
|
declare const wailsapp__runtime: {
|
||||||
Browser: {
|
Browser: {
|
||||||
OpenFile(filename: string): Promise<any>;
|
Open(target: string): Promise<any>;
|
||||||
OpenURL(url: string): Promise<any>;
|
|
||||||
};
|
};
|
||||||
Events: {
|
Events: {
|
||||||
Acknowledge(eventName: string): void;
|
Emit(eventName: string, data?: any): void;
|
||||||
Emit(eventName: string): void;
|
On(eventName: string, callback: (data?: any) => void): void;
|
||||||
Heartbeat(eventName: string, timeInMilliseconds: number, callback: () => void): void;
|
OnMultiple(eventName: string, callback: (data?: any) => void, maxCallbacks: number): void;
|
||||||
On(eventName: string, callback: () => void): void;
|
Once(eventName: string, callback: (data?: any) => void): void;
|
||||||
OnMultiple(eventName: string, callback: () => void, maxCallbacks: number): void;
|
|
||||||
Once(eventName: string, callback: () => void): void;
|
|
||||||
};
|
};
|
||||||
Init(callback: () => void): void;
|
// Init(callback: () => void): void;
|
||||||
Log: {
|
Log: {
|
||||||
Debug(message: string): void;
|
Debug(message: string): void;
|
||||||
Error(message: string): void;
|
Error(message: string): void;
|
||||||
Fatal(message: string): void;
|
Fatal(message: string): void;
|
||||||
Info(message: string): void;
|
Info(message: string): void;
|
||||||
Warning(message: string): void;
|
Warning(message: string): void;
|
||||||
|
Level: Level;
|
||||||
};
|
};
|
||||||
|
System: {
|
||||||
|
DarkModeEnabled(): Promise<boolean>;
|
||||||
|
OnThemeChange(callback: (darkModeEnabled: boolean) => void): void;
|
||||||
|
LogLevel(): Store;
|
||||||
|
Platform(): string;
|
||||||
|
AppType(): string
|
||||||
|
};
|
||||||
|
Store: {
|
||||||
|
New(name: string, defaultValue?: any): Store;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
27
v2/internal/runtime/js/runtime/store.js
Normal file
27
v2/internal/runtime/js/runtime/store.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Store with the given name and optional default value
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} name
|
||||||
|
* @param {*} optionalDefault
|
||||||
|
*/
|
||||||
|
function New(name, optionalDefault) {
|
||||||
|
return window.wails.Store.New(name, optionalDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
New: New,
|
||||||
|
};
|
||||||
42
v2/internal/runtime/js/runtime/system.js
Normal file
42
v2/internal/runtime/js/runtime/system.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
const Events = require('./events');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an event listener that will be invoked when the user changes the
|
||||||
|
* desktop theme (light mode / dark mode). The callback receives a boolean which
|
||||||
|
* indicates if dark mode is enabled.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {function} callback The callback to invoke on theme change
|
||||||
|
*/
|
||||||
|
function OnThemeChange(callback) {
|
||||||
|
Events.On("wails:system:themechange", callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if dark mode is curently enabled.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
function DarkModeEnabled() {
|
||||||
|
return window.wails.System.IsDarkMode.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
OnThemeChange: OnThemeChange,
|
||||||
|
DarkModeEnabled: DarkModeEnabled,
|
||||||
|
LogLevel: window.wails.System.LogLevel,
|
||||||
|
Platform: window.wails.System.Platform,
|
||||||
|
AppType: window.wails.System.AppType
|
||||||
|
};
|
||||||
21
v2/internal/runtime/js/server/darwin.js
Normal file
21
v2/internal/runtime/js/server/darwin.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises platform specific code
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const System = {
|
||||||
|
Platform: "darwin",
|
||||||
|
AppType: "server"
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Init() { }
|
||||||
69
v2/internal/runtime/log.go
Normal file
69
v2/internal/runtime/log.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Log defines all Log related operations
|
||||||
|
type Log interface {
|
||||||
|
Print(message string)
|
||||||
|
Trace(message string)
|
||||||
|
Debug(message string)
|
||||||
|
Info(message string)
|
||||||
|
Warning(message string)
|
||||||
|
Error(message string)
|
||||||
|
Fatal(message string)
|
||||||
|
SetLogLevel(level logger.LogLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
type log struct {
|
||||||
|
bus *servicebus.ServiceBus
|
||||||
|
}
|
||||||
|
|
||||||
|
// newLog creates a new Log struct
|
||||||
|
func newLog(bus *servicebus.ServiceBus) Log {
|
||||||
|
return &log{
|
||||||
|
bus: bus,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print prints a Print level message
|
||||||
|
func (r *log) Print(message string) {
|
||||||
|
r.bus.Publish("log:print", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trace prints a Trace level message
|
||||||
|
func (r *log) Trace(message string) {
|
||||||
|
r.bus.Publish("log:trace", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug prints a Debug level message
|
||||||
|
func (r *log) Debug(message string) {
|
||||||
|
r.bus.Publish("log:debug", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info prints a Info level message
|
||||||
|
func (r *log) Info(message string) {
|
||||||
|
r.bus.Publish("log:info", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning prints a Warning level message
|
||||||
|
func (r *log) Warning(message string) {
|
||||||
|
r.bus.Publish("log:warning", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error prints a Error level message
|
||||||
|
func (r *log) Error(message string) {
|
||||||
|
r.bus.Publish("log:error", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatal prints a Fatal level message
|
||||||
|
func (r *log) Fatal(message string) {
|
||||||
|
r.bus.Publish("log:fatal", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the log level
|
||||||
|
func (r *log) SetLogLevel(level logger.LogLevel) {
|
||||||
|
r.bus.Publish("log:setlevel", level)
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package goruntime
|
package runtime
|
||||||
|
|
||||||
import "github.com/wailsapp/wails/v2/internal/servicebus"
|
import "github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
|
||||||
@@ -8,18 +8,25 @@ type Runtime struct {
|
|||||||
Events Events
|
Events Events
|
||||||
Window Window
|
Window Window
|
||||||
Dialog Dialog
|
Dialog Dialog
|
||||||
|
System System
|
||||||
|
Store *StoreProvider
|
||||||
|
Log Log
|
||||||
bus *servicebus.ServiceBus
|
bus *servicebus.ServiceBus
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new runtime
|
// New creates a new runtime
|
||||||
func New(serviceBus *servicebus.ServiceBus) *Runtime {
|
func New(serviceBus *servicebus.ServiceBus) *Runtime {
|
||||||
return &Runtime{
|
result := &Runtime{
|
||||||
Browser: newBrowser(),
|
Browser: newBrowser(),
|
||||||
Events: newEvents(serviceBus),
|
Events: newEvents(serviceBus),
|
||||||
Window: newWindow(serviceBus),
|
Window: newWindow(serviceBus),
|
||||||
Dialog: newDialog(serviceBus),
|
Dialog: newDialog(serviceBus),
|
||||||
|
System: newSystem(serviceBus),
|
||||||
|
Log: newLog(serviceBus),
|
||||||
bus: serviceBus,
|
bus: serviceBus,
|
||||||
}
|
}
|
||||||
|
result.Store = newStore(result)
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quit the application
|
// Quit the application
|
||||||
295
v2/internal/runtime/store.go
Normal file
295
v2/internal/runtime/store.go
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
// package runtime contains all the methods and data structures related to the
|
||||||
|
// runtime library of Wails. This includes both Go and JS runtimes.
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Options defines the optional data that may be used
|
||||||
|
// when creating a Store
|
||||||
|
type Options struct {
|
||||||
|
|
||||||
|
// The name of the store
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// The runtime to attach the store to
|
||||||
|
Runtime *Runtime
|
||||||
|
|
||||||
|
// Indicates if notifying Go listeners should be notified of updates
|
||||||
|
// synchronously (on the current thread) or asynchronously using
|
||||||
|
// goroutines
|
||||||
|
NotifySynchronously bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// StoreProvider is a struct that creates Stores
|
||||||
|
type StoreProvider struct {
|
||||||
|
runtime *Runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
// newStore creates new stores using the provided Runtime reference.
|
||||||
|
func newStore(runtime *Runtime) *StoreProvider {
|
||||||
|
return &StoreProvider{
|
||||||
|
runtime: runtime,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store is where we keep named data
|
||||||
|
type Store struct {
|
||||||
|
name string
|
||||||
|
data reflect.Value
|
||||||
|
dataType reflect.Type
|
||||||
|
eventPrefix string
|
||||||
|
callbacks []reflect.Value
|
||||||
|
runtime *Runtime
|
||||||
|
notifySynchronously bool
|
||||||
|
|
||||||
|
// Lock
|
||||||
|
mux sync.Mutex
|
||||||
|
|
||||||
|
// Error handler
|
||||||
|
errorHandler func(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fatal(err error) {
|
||||||
|
println(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new store
|
||||||
|
func (p *StoreProvider) New(name string, defaultValue interface{}) *Store {
|
||||||
|
|
||||||
|
dataType := reflect.TypeOf(defaultValue)
|
||||||
|
|
||||||
|
result := Store{
|
||||||
|
name: name,
|
||||||
|
runtime: p.runtime,
|
||||||
|
data: reflect.ValueOf(defaultValue),
|
||||||
|
dataType: dataType,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the sync listener
|
||||||
|
result.setupListener()
|
||||||
|
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnError takes a function that will be called
|
||||||
|
// whenever an error occurs
|
||||||
|
func (s *Store) OnError(callback func(error)) {
|
||||||
|
s.errorHandler = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
// Processes the updates sent by the front end
|
||||||
|
func (s *Store) processUpdatedData(data string) error {
|
||||||
|
|
||||||
|
// Decode incoming data
|
||||||
|
var rawdata json.RawMessage
|
||||||
|
d := json.NewDecoder(bytes.NewBufferString(data))
|
||||||
|
err := d.Decode(&rawdata)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new instance of our data and unmarshal
|
||||||
|
// the received value into it
|
||||||
|
newData := reflect.New(s.dataType).Interface()
|
||||||
|
err = json.Unmarshal(rawdata, &newData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock mutex for writing
|
||||||
|
s.mux.Lock()
|
||||||
|
|
||||||
|
// Handle nulls
|
||||||
|
if newData == nil {
|
||||||
|
s.data = reflect.Zero(s.dataType)
|
||||||
|
} else {
|
||||||
|
// Store the resultant value in the data store
|
||||||
|
s.data = reflect.ValueOf(newData).Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock mutex
|
||||||
|
s.mux.Unlock()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup listener for front end changes
|
||||||
|
func (s *Store) setupListener() {
|
||||||
|
|
||||||
|
// Listen for updates from the front end
|
||||||
|
s.runtime.Events.On("wails:sync:store:updatedbyfrontend:"+s.name, func(data ...interface{}) {
|
||||||
|
|
||||||
|
// Process the incoming data
|
||||||
|
err := s.processUpdatedData(data[0].(string))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if s.errorHandler != nil {
|
||||||
|
s.errorHandler(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify listeners
|
||||||
|
s.notify()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify the listeners of the current data state
|
||||||
|
func (s *Store) notify() {
|
||||||
|
|
||||||
|
// Execute callbacks
|
||||||
|
for _, callback := range s.callbacks {
|
||||||
|
|
||||||
|
// Build args
|
||||||
|
args := []reflect.Value{s.data}
|
||||||
|
|
||||||
|
if s.notifySynchronously {
|
||||||
|
callback.Call(args)
|
||||||
|
} else {
|
||||||
|
go callback.Call(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set will update the data held by the store
|
||||||
|
// and notify listeners of the change
|
||||||
|
func (s *Store) Set(data interface{}) error {
|
||||||
|
|
||||||
|
inType := reflect.TypeOf(data)
|
||||||
|
|
||||||
|
if inType != s.dataType {
|
||||||
|
return fmt.Errorf("invalid data given in Store.Set(). Expected %s, got %s", s.dataType.String(), inType.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save data
|
||||||
|
s.mux.Lock()
|
||||||
|
s.data = reflect.ValueOf(data)
|
||||||
|
s.mux.Unlock()
|
||||||
|
|
||||||
|
// Stringify data
|
||||||
|
newdata, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
if s.errorHandler != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit event to front end
|
||||||
|
s.runtime.Events.Emit("wails:sync:store:updatedbybackend:"+s.name, string(newdata))
|
||||||
|
|
||||||
|
// Notify subscribers
|
||||||
|
s.notify()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// callbackCheck ensures the given function to Subscribe() is
|
||||||
|
// of the correct signature. Absolutely cannot wait for
|
||||||
|
// generics to land rather than writing this nonsense.
|
||||||
|
func (s *Store) callbackCheck(callback interface{}) error {
|
||||||
|
|
||||||
|
// Get type
|
||||||
|
callbackType := reflect.TypeOf(callback)
|
||||||
|
|
||||||
|
// Check callback is a function
|
||||||
|
if callbackType.Kind() != reflect.Func {
|
||||||
|
return fmt.Errorf("invalid value given to store.Subscribe(). Expected 'func(%s)'", s.dataType.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check input param
|
||||||
|
if callbackType.NumIn() != 1 {
|
||||||
|
return fmt.Errorf("invalid number of parameters given in callback function. Expected 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check input data type
|
||||||
|
if callbackType.In(0) != s.dataType {
|
||||||
|
return fmt.Errorf("invalid type for input parameter given in callback function. Expected %s, got %s", s.dataType.String(), callbackType.In(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check output param
|
||||||
|
if callbackType.NumOut() != 0 {
|
||||||
|
return fmt.Errorf("invalid number of return parameters given in callback function. Expected 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe will subscribe to updates to the store by
|
||||||
|
// providing a callback. Any updates to the store are sent
|
||||||
|
// to the callback
|
||||||
|
func (s *Store) Subscribe(callback interface{}) {
|
||||||
|
|
||||||
|
err := s.callbackCheck(callback)
|
||||||
|
if err != nil {
|
||||||
|
fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
callbackFunc := reflect.ValueOf(callback)
|
||||||
|
|
||||||
|
s.callbacks = append(s.callbacks, callbackFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// updaterCheck ensures the given function to Update() is
|
||||||
|
// of the correct signature. Absolutely cannot wait for
|
||||||
|
// generics to land rather than writing this nonsense.
|
||||||
|
func (s *Store) updaterCheck(updater interface{}) error {
|
||||||
|
|
||||||
|
// Get type
|
||||||
|
updaterType := reflect.TypeOf(updater)
|
||||||
|
|
||||||
|
// Check updater is a function
|
||||||
|
if updaterType.Kind() != reflect.Func {
|
||||||
|
return fmt.Errorf("invalid value given to store.Update(). Expected 'func(%s) %s'", s.dataType.String(), s.dataType.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check input param
|
||||||
|
if updaterType.NumIn() != 1 {
|
||||||
|
return fmt.Errorf("invalid number of parameters given in updater function. Expected 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check input data type
|
||||||
|
if updaterType.In(0) != s.dataType {
|
||||||
|
return fmt.Errorf("invalid type for input parameter given in updater function. Expected %s, got %s", s.dataType.String(), updaterType.In(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check output param
|
||||||
|
if updaterType.NumOut() != 1 {
|
||||||
|
return fmt.Errorf("invalid number of return parameters given in updater function. Expected 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check output data type
|
||||||
|
if updaterType.Out(0) != s.dataType {
|
||||||
|
return fmt.Errorf("invalid type for return parameter given in updater function. Expected %s, got %s", s.dataType.String(), updaterType.Out(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update takes a function that is passed the current state.
|
||||||
|
// The result of that function is then set as the new state
|
||||||
|
// of the store. This will notify listeners of the change
|
||||||
|
func (s *Store) Update(updater interface{}) {
|
||||||
|
|
||||||
|
err := s.updaterCheck(updater)
|
||||||
|
if err != nil {
|
||||||
|
fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build args
|
||||||
|
args := []reflect.Value{s.data}
|
||||||
|
|
||||||
|
// Make call
|
||||||
|
results := reflect.ValueOf(updater).Call(args)
|
||||||
|
|
||||||
|
// We will only have 1 result. Set the store to it
|
||||||
|
s.Set(results[0].Interface())
|
||||||
|
}
|
||||||
59
v2/internal/runtime/system.go
Normal file
59
v2/internal/runtime/system.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/internal/crypto"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// System defines all System related operations
|
||||||
|
type System interface {
|
||||||
|
IsDarkMode() bool
|
||||||
|
Platform() string
|
||||||
|
AppType() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// system exposes the System interface
|
||||||
|
type system struct {
|
||||||
|
bus *servicebus.ServiceBus
|
||||||
|
}
|
||||||
|
|
||||||
|
// newSystem creates a new System struct
|
||||||
|
func newSystem(bus *servicebus.ServiceBus) System {
|
||||||
|
return &system{
|
||||||
|
bus: bus,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Platform returns the platform name the application
|
||||||
|
// is running on
|
||||||
|
func (r *system) Platform() string {
|
||||||
|
return runtime.GOOS
|
||||||
|
}
|
||||||
|
|
||||||
|
// On pass through
|
||||||
|
func (r *system) IsDarkMode() bool {
|
||||||
|
|
||||||
|
// Create unique system callback
|
||||||
|
uniqueCallback := crypto.RandomID()
|
||||||
|
|
||||||
|
// Subscribe to the respose channel
|
||||||
|
responseTopic := "systemresponse:" + uniqueCallback
|
||||||
|
systemResponseChannel, err := r.bus.Subscribe(responseTopic)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
message := "system:isdarkmode:" + uniqueCallback
|
||||||
|
r.bus.Publish(message, nil)
|
||||||
|
|
||||||
|
// Wait for result
|
||||||
|
var result *servicebus.Message = <-systemResponseChannel
|
||||||
|
|
||||||
|
// Delete subscription to response topic
|
||||||
|
r.bus.UnSubscribe(responseTopic)
|
||||||
|
|
||||||
|
return result.Data().(bool)
|
||||||
|
}
|
||||||
8
v2/internal/runtime/system_desktop.go
Normal file
8
v2/internal/runtime/system_desktop.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// +build desktop,!server
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
// AppType returns the application type, EG: desktop
|
||||||
|
func (r *system) AppType() string {
|
||||||
|
return "desktop"
|
||||||
|
}
|
||||||
8
v2/internal/runtime/system_server.go
Normal file
8
v2/internal/runtime/system_server.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// +build server
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
// AppType returns the application type, EG: desktop
|
||||||
|
func (r *system) AppType() string {
|
||||||
|
return "server"
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package goruntime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
@@ -16,7 +16,7 @@ type Window interface {
|
|||||||
SetTitle(title string)
|
SetTitle(title string)
|
||||||
Fullscreen()
|
Fullscreen()
|
||||||
UnFullscreen()
|
UnFullscreen()
|
||||||
SetColour(colour string)
|
SetColour(colour int)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Window exposes the Windows interface
|
// Window exposes the Windows interface
|
||||||
@@ -54,8 +54,8 @@ func (w *window) UnFullscreen() {
|
|||||||
w.bus.Publish("window:unfullscreen", "")
|
w.bus.Publish("window:unfullscreen", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetColour sets the window colour to the given string
|
// SetColour sets the window colour to the given int
|
||||||
func (w *window) SetColour(colour string) {
|
func (w *window) SetColour(colour int) {
|
||||||
w.bus.Publish("window:setcolour", colour)
|
w.bus.Publish("window:setcolour", colour)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3,7 +3,7 @@ package subsystem
|
|||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/v2/internal/binding"
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/runtime/goruntime"
|
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,11 +21,11 @@ type Binding struct {
|
|||||||
logger logger.CustomLogger
|
logger logger.CustomLogger
|
||||||
|
|
||||||
// runtime
|
// runtime
|
||||||
runtime *goruntime.Runtime
|
runtime *runtime.Runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBinding creates a new binding subsystem. Uses the given bindings db for reference.
|
// NewBinding creates a new binding subsystem. Uses the given bindings db for reference.
|
||||||
func NewBinding(bus *servicebus.ServiceBus, logger *logger.Logger, bindings *binding.Bindings, runtime *goruntime.Runtime) (*Binding, error) {
|
func NewBinding(bus *servicebus.ServiceBus, logger *logger.Logger, bindings *binding.Bindings, runtime *runtime.Runtime) (*Binding, error) {
|
||||||
|
|
||||||
// Register quit channel
|
// Register quit channel
|
||||||
quitChannel, err := bus.Subscribe("quit")
|
quitChannel, err := bus.Subscribe("quit")
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ package subsystem
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/binding"
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,10 +27,13 @@ type Call struct {
|
|||||||
|
|
||||||
// logger
|
// logger
|
||||||
logger logger.CustomLogger
|
logger logger.CustomLogger
|
||||||
|
|
||||||
|
// runtime
|
||||||
|
runtime *runtime.Runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCall creates a new log subsystem
|
// NewCall creates a new call subsystem
|
||||||
func NewCall(bus *servicebus.ServiceBus, logger *logger.Logger, DB *binding.DB) (*Call, error) {
|
func NewCall(bus *servicebus.ServiceBus, logger *logger.Logger, DB *binding.DB, runtime *runtime.Runtime) (*Call, error) {
|
||||||
|
|
||||||
// Register quit channel
|
// Register quit channel
|
||||||
quitChannel, err := bus.Subscribe("quit")
|
quitChannel, err := bus.Subscribe("quit")
|
||||||
@@ -48,6 +53,7 @@ func NewCall(bus *servicebus.ServiceBus, logger *logger.Logger, DB *binding.DB)
|
|||||||
logger: logger.CustomLogger("Call Subsystem"),
|
logger: logger.CustomLogger("Call Subsystem"),
|
||||||
DB: DB,
|
DB: DB,
|
||||||
bus: bus,
|
bus: bus,
|
||||||
|
runtime: runtime,
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -65,7 +71,7 @@ func (c *Call) Start() error {
|
|||||||
case <-c.quitChannel:
|
case <-c.quitChannel:
|
||||||
c.running = false
|
c.running = false
|
||||||
case callMessage := <-c.callChannel:
|
case callMessage := <-c.callChannel:
|
||||||
|
// TODO: Check if this works ok in a goroutine
|
||||||
c.processCall(callMessage)
|
c.processCall(callMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,6 +93,12 @@ func (c *Call) processCall(callMessage *servicebus.Message) {
|
|||||||
// Lookup method
|
// Lookup method
|
||||||
registeredMethod := c.DB.GetMethod(payload.Name)
|
registeredMethod := c.DB.GetMethod(payload.Name)
|
||||||
|
|
||||||
|
// Check if it's a system call
|
||||||
|
if strings.HasPrefix(payload.Name, ".wails.") {
|
||||||
|
c.processSystemCall(payload, callMessage.Target())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Check we have it
|
// Check we have it
|
||||||
if registeredMethod == nil {
|
if registeredMethod == nil {
|
||||||
c.sendError(fmt.Errorf("Method not registered"), payload, callMessage.Target())
|
c.sendError(fmt.Errorf("Method not registered"), payload, callMessage.Target())
|
||||||
@@ -94,7 +106,12 @@ func (c *Call) processCall(callMessage *servicebus.Message) {
|
|||||||
}
|
}
|
||||||
c.logger.Trace("Got registered method: %+v", registeredMethod)
|
c.logger.Trace("Got registered method: %+v", registeredMethod)
|
||||||
|
|
||||||
result, err := registeredMethod.Call(payload.Args)
|
args, err := registeredMethod.ParseArgs(payload.Args)
|
||||||
|
if err != nil {
|
||||||
|
c.sendError(fmt.Errorf("Error parsing arguments: %s", err.Error()), payload, callMessage.Target())
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := registeredMethod.Call(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.sendError(err, payload, callMessage.Target())
|
c.sendError(err, payload, callMessage.Target())
|
||||||
return
|
return
|
||||||
@@ -105,6 +122,16 @@ func (c *Call) processCall(callMessage *servicebus.Message) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Call) processSystemCall(payload *message.CallMessage, clientID string) {
|
||||||
|
c.logger.Trace("Got internal System call: %+v", payload)
|
||||||
|
callName := strings.TrimPrefix(payload.Name, ".wails.")
|
||||||
|
switch callName {
|
||||||
|
case "IsDarkMode":
|
||||||
|
darkModeEnabled := c.runtime.System.IsDarkMode()
|
||||||
|
c.sendResult(darkModeEnabled, payload, clientID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Call) sendResult(result interface{}, payload *message.CallMessage, clientID string) {
|
func (c *Call) sendResult(result interface{}, payload *message.CallMessage, clientID string) {
|
||||||
c.logger.Trace("Sending success result with CallbackID '%s' : %+v\n", payload.CallbackID, result)
|
c.logger.Trace("Sending success result with CallbackID '%s' : %+v\n", payload.CallbackID, result)
|
||||||
message := &CallbackMessage{
|
message := &CallbackMessage{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
// means it does not expire (default).
|
// means it does not expire (default).
|
||||||
type eventListener struct {
|
type eventListener struct {
|
||||||
callback func(...interface{}) // Function to call with emitted event data
|
callback func(...interface{}) // Function to call with emitted event data
|
||||||
counter int64 // The number of times this callback may be called. -1 = infinite
|
counter int // The number of times this callback may be called. -1 = infinite
|
||||||
delete bool // Flag to indicate that this listener should be deleted
|
delete bool // Flag to indicate that this listener should be deleted
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,12 +60,12 @@ func NewEvent(bus *servicebus.ServiceBus, logger *logger.Logger) (*Event, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RegisterListener provides a means of subscribing to events of type "eventName"
|
// RegisterListener provides a means of subscribing to events of type "eventName"
|
||||||
func (e *Event) RegisterListener(eventName string, callback func(...interface{})) {
|
func (e *Event) RegisterListener(eventName string, callback func(...interface{}), counter int) {
|
||||||
|
|
||||||
// Create new eventListener
|
// Create new eventListener
|
||||||
thisListener := &eventListener{
|
thisListener := &eventListener{
|
||||||
callback: callback,
|
callback: callback,
|
||||||
counter: 0,
|
counter: counter,
|
||||||
delete: false,
|
delete: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ func (e *Event) Start() error {
|
|||||||
var message *message.OnEventMessage = eventMessage.Data().(*message.OnEventMessage)
|
var message *message.OnEventMessage = eventMessage.Data().(*message.OnEventMessage)
|
||||||
eventName := message.Name
|
eventName := message.Name
|
||||||
callback := message.Callback
|
callback := message.Callback
|
||||||
e.RegisterListener(eventName, callback)
|
e.RegisterListener(eventName, callback, message.Counter)
|
||||||
e.logger.Trace("Registered listener for event '%s' with callback %p", eventName, callback)
|
e.logger.Trace("Registered listener for event '%s' with callback %p", eventName, callback)
|
||||||
default:
|
default:
|
||||||
e.logger.Error("unknown event message: %+v", eventMessage)
|
e.logger.Error("unknown event message: %+v", eventMessage)
|
||||||
@@ -141,7 +141,7 @@ func (e *Event) notifyListeners(eventName string, message *message.EventMessage)
|
|||||||
// Get list of event listeners
|
// Get list of event listeners
|
||||||
listeners := e.listeners[eventName]
|
listeners := e.listeners[eventName]
|
||||||
if listeners == nil {
|
if listeners == nil {
|
||||||
println("no listeners for", eventName)
|
e.logger.Trace("No listeners for %s", eventName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,13 +179,16 @@ func (e *Event) notifyListeners(eventName string, message *message.EventMessage)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save new listeners
|
// Save new listeners or remove entry
|
||||||
e.listeners[eventName] = newListeners
|
if len(newListeners) > 0 {
|
||||||
|
e.listeners[eventName] = newListeners
|
||||||
|
} else {
|
||||||
|
delete(e.listeners, eventName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
e.notifyLock.Unlock()
|
e.notifyLock.Unlock()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Event) shutdown() {
|
func (e *Event) shutdown() {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package subsystem
|
package subsystem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,10 +18,13 @@ type Log struct {
|
|||||||
|
|
||||||
// Logger!
|
// Logger!
|
||||||
logger *logger.Logger
|
logger *logger.Logger
|
||||||
|
|
||||||
|
// Loglevel store
|
||||||
|
logLevelStore *runtime.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLog creates a new log subsystem
|
// NewLog creates a new log subsystem
|
||||||
func NewLog(bus *servicebus.ServiceBus, logger *logger.Logger) (*Log, error) {
|
func NewLog(bus *servicebus.ServiceBus, logger *logger.Logger, logLevelStore *runtime.Store) (*Log, error) {
|
||||||
|
|
||||||
// Subscribe to log messages
|
// Subscribe to log messages
|
||||||
logChannel, err := bus.Subscribe("log")
|
logChannel, err := bus.Subscribe("log")
|
||||||
@@ -34,9 +39,10 @@ func NewLog(bus *servicebus.ServiceBus, logger *logger.Logger) (*Log, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := &Log{
|
result := &Log{
|
||||||
logChannel: logChannel,
|
logChannel: logChannel,
|
||||||
quitChannel: quitChannel,
|
quitChannel: quitChannel,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
logLevelStore: logLevelStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -57,6 +63,10 @@ func (l *Log) Start() error {
|
|||||||
case logMessage := <-l.logChannel:
|
case logMessage := <-l.logChannel:
|
||||||
logType := strings.TrimPrefix(logMessage.Topic(), "log:")
|
logType := strings.TrimPrefix(logMessage.Topic(), "log:")
|
||||||
switch logType {
|
switch logType {
|
||||||
|
case "print":
|
||||||
|
l.logger.Print(logMessage.Data().(string))
|
||||||
|
case "trace":
|
||||||
|
l.logger.Trace(logMessage.Data().(string))
|
||||||
case "debug":
|
case "debug":
|
||||||
l.logger.Debug(logMessage.Data().(string))
|
l.logger.Debug(logMessage.Data().(string))
|
||||||
case "info":
|
case "info":
|
||||||
@@ -67,6 +77,22 @@ func (l *Log) Start() error {
|
|||||||
l.logger.Error(logMessage.Data().(string))
|
l.logger.Error(logMessage.Data().(string))
|
||||||
case "fatal":
|
case "fatal":
|
||||||
l.logger.Fatal(logMessage.Data().(string))
|
l.logger.Fatal(logMessage.Data().(string))
|
||||||
|
case "setlevel":
|
||||||
|
switch inLevel := logMessage.Data().(type) {
|
||||||
|
case logger.LogLevel:
|
||||||
|
l.logger.SetLogLevel(inLevel)
|
||||||
|
l.logLevelStore.Set(inLevel)
|
||||||
|
case string:
|
||||||
|
uint64level, err := strconv.ParseUint(inLevel, 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
l.logger.Error("Error parsing log level: %+v", inLevel)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
level := logger.LogLevel(uint64level)
|
||||||
|
l.logLevelStore.Set(level)
|
||||||
|
l.logger.SetLogLevel(level)
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
l.logger.Error("unknown log message: %+v", logMessage)
|
l.logger.Error("unknown log message: %+v", logMessage)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/runtime/goruntime"
|
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ type Runtime struct {
|
|||||||
logger logger.CustomLogger
|
logger logger.CustomLogger
|
||||||
|
|
||||||
// Runtime library
|
// Runtime library
|
||||||
runtime *goruntime.Runtime
|
runtime *runtime.Runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRuntime creates a new runtime subsystem
|
// NewRuntime creates a new runtime subsystem
|
||||||
@@ -32,7 +32,7 @@ func NewRuntime(bus *servicebus.ServiceBus, logger *logger.Logger) (*Runtime, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to log messages
|
// Subscribe to log messages
|
||||||
runtimeChannel, err := bus.Subscribe("runtime")
|
runtimeChannel, err := bus.Subscribe("runtime:")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ func NewRuntime(bus *servicebus.ServiceBus, logger *logger.Logger) (*Runtime, er
|
|||||||
quitChannel: quitChannel,
|
quitChannel: quitChannel,
|
||||||
runtimeChannel: runtimeChannel,
|
runtimeChannel: runtimeChannel,
|
||||||
logger: logger.CustomLogger("Runtime Subsystem"),
|
logger: logger.CustomLogger("Runtime Subsystem"),
|
||||||
runtime: goruntime.New(bus),
|
runtime: runtime.New(bus),
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -75,7 +75,7 @@ func (r *Runtime) Start() error {
|
|||||||
case "browser":
|
case "browser":
|
||||||
err = r.processBrowserMessage(method, runtimeMessage.Data())
|
err = r.processBrowserMessage(method, runtimeMessage.Data())
|
||||||
default:
|
default:
|
||||||
fmt.Errorf("unknown log message: %+v", runtimeMessage)
|
fmt.Errorf("unknown runtime message: %+v", runtimeMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we had an error, log it
|
// If we had an error, log it
|
||||||
@@ -93,7 +93,7 @@ func (r *Runtime) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GoRuntime returns the Go Runtime object
|
// GoRuntime returns the Go Runtime object
|
||||||
func (r *Runtime) GoRuntime() *goruntime.Runtime {
|
func (r *Runtime) GoRuntime() *runtime.Runtime {
|
||||||
return r.runtime
|
return r.runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,12 +103,12 @@ func (r *Runtime) shutdown() {
|
|||||||
|
|
||||||
func (r *Runtime) processBrowserMessage(method string, data interface{}) error {
|
func (r *Runtime) processBrowserMessage(method string, data interface{}) error {
|
||||||
switch method {
|
switch method {
|
||||||
case "openurl":
|
case "open":
|
||||||
url, ok := data.(string)
|
target, ok := data.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("expected 1 string parameter for runtime:browser:openurl")
|
return fmt.Errorf("expected 1 string parameter for runtime:browser:open")
|
||||||
}
|
}
|
||||||
go r.runtime.Browser.Open(url)
|
go r.runtime.Browser.Open(target)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown method runtime:browser:%s", method)
|
return fmt.Errorf("unknown method runtime:browser:%s", method)
|
||||||
}
|
}
|
||||||
|
|||||||
30
v2/internal/system/operatingsystem/os_darwin.go
Normal file
30
v2/internal/system/operatingsystem/os_darwin.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package operatingsystem
|
||||||
|
|
||||||
|
import "github.com/wailsapp/wails/v2/internal/shell"
|
||||||
|
|
||||||
|
func platformInfo() (*OS, error) {
|
||||||
|
// Default value
|
||||||
|
var result OS
|
||||||
|
result.ID = "Unknown"
|
||||||
|
result.Name = "MacOS"
|
||||||
|
result.Version = "Unknown"
|
||||||
|
|
||||||
|
stdout, stderr, err := shell.RunCommand(".", "sysctl", "kern.osrelease")
|
||||||
|
println(stdout)
|
||||||
|
println(stderr)
|
||||||
|
println(err)
|
||||||
|
// cmd := CreateCommand(directory, command, args...)
|
||||||
|
// var stdo, stde bytes.Buffer
|
||||||
|
// cmd.Stdout = &stdo
|
||||||
|
// cmd.Stderr = &stde
|
||||||
|
// err := cmd.Run()
|
||||||
|
// return stdo.String(), stde.String(), err
|
||||||
|
// }
|
||||||
|
// sysctl := shell.NewCommand("sysctl")
|
||||||
|
// kern.ostype: Darwin
|
||||||
|
// kern.osrelease: 20.1.0
|
||||||
|
// kern.osrevision: 199506
|
||||||
|
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
29
v2/internal/system/operatingsystem/os_windows.go
Normal file
29
v2/internal/system/operatingsystem/os_windows.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package operatingsystem
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func platformInfo() (*OS, error) {
|
||||||
|
// Default value
|
||||||
|
var result OS
|
||||||
|
result.ID = "Unknown"
|
||||||
|
result.Name = "Windows"
|
||||||
|
result.Version = "Unknown"
|
||||||
|
|
||||||
|
// Credit: https://stackoverflow.com/a/33288328
|
||||||
|
// Ignore errors as it isn't a showstopper
|
||||||
|
key, _ := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
||||||
|
|
||||||
|
defer key.Close()
|
||||||
|
|
||||||
|
fmt.Printf("%+v\n", key)
|
||||||
|
|
||||||
|
// Ignore errors as it isn't a showstopper
|
||||||
|
productName, _, _ := key.GetStringValue("ProductName")
|
||||||
|
fmt.Println(productName)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
@@ -9,24 +9,6 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2/internal/shell"
|
"github.com/wailsapp/wails/v2/internal/shell"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PackageManager is a common interface across all package managers
|
|
||||||
type PackageManager interface {
|
|
||||||
Name() string
|
|
||||||
Packages() packagemap
|
|
||||||
PackageInstalled(*Package) (bool, error)
|
|
||||||
PackageAvailable(*Package) (bool, error)
|
|
||||||
InstallCommand(*Package) string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Package contains information about a system package
|
|
||||||
type Package struct {
|
|
||||||
Name string
|
|
||||||
Version string
|
|
||||||
InstallCommand map[string]string
|
|
||||||
SystemPackage bool
|
|
||||||
Library bool
|
|
||||||
Optional bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// A list of package manager commands
|
// A list of package manager commands
|
||||||
var pmcommands = []string{
|
var pmcommands = []string{
|
||||||
@@ -38,8 +20,6 @@ var pmcommands = []string{
|
|||||||
"zypper",
|
"zypper",
|
||||||
}
|
}
|
||||||
|
|
||||||
type packagemap = map[string][]*Package
|
|
||||||
|
|
||||||
// Find will attempt to find the system package manager
|
// Find will attempt to find the system package manager
|
||||||
func Find(osid string) PackageManager {
|
func Find(osid string) PackageManager {
|
||||||
|
|
||||||
@@ -70,58 +50,6 @@ func newPackageManager(pmname string, osid string) PackageManager {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dependancy represents a system package that we require
|
|
||||||
type Dependancy struct {
|
|
||||||
Name string
|
|
||||||
PackageName string
|
|
||||||
Installed bool
|
|
||||||
InstallCommand string
|
|
||||||
Version string
|
|
||||||
Optional bool
|
|
||||||
External bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// DependencyList is a list of Dependency instances
|
|
||||||
type DependencyList []*Dependancy
|
|
||||||
|
|
||||||
// InstallAllRequiredCommand returns the command you need to use to install all required dependencies
|
|
||||||
func (d DependencyList) InstallAllRequiredCommand() string {
|
|
||||||
|
|
||||||
result := ""
|
|
||||||
for _, dependency := range d {
|
|
||||||
if dependency.PackageName != "" {
|
|
||||||
if !dependency.Installed && !dependency.Optional {
|
|
||||||
if result == "" {
|
|
||||||
result = dependency.InstallCommand
|
|
||||||
} else {
|
|
||||||
result += " " + dependency.PackageName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstallAllOptionalCommand returns the command you need to use to install all optional dependencies
|
|
||||||
func (d DependencyList) InstallAllOptionalCommand() string {
|
|
||||||
|
|
||||||
result := ""
|
|
||||||
for _, dependency := range d {
|
|
||||||
if dependency.PackageName != "" {
|
|
||||||
if !dependency.Installed && dependency.Optional {
|
|
||||||
if result == "" {
|
|
||||||
result = dependency.InstallCommand
|
|
||||||
} else {
|
|
||||||
result += " " + dependency.PackageName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dependancies scans the system for required dependancies
|
// Dependancies scans the system for required dependancies
|
||||||
// Returns a list of dependancies search for, whether they were found
|
// Returns a list of dependancies search for, whether they were found
|
||||||
// and whether they were installed
|
// and whether they were installed
|
||||||
|
|||||||
77
v2/internal/system/packagemanager/pm.go
Normal file
77
v2/internal/system/packagemanager/pm.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package packagemanager
|
||||||
|
|
||||||
|
// Package contains information about a system package
|
||||||
|
type Package struct {
|
||||||
|
Name string
|
||||||
|
Version string
|
||||||
|
InstallCommand map[string]string
|
||||||
|
SystemPackage bool
|
||||||
|
Library bool
|
||||||
|
Optional bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type packagemap = map[string][]*Package
|
||||||
|
|
||||||
|
// PackageManager is a common interface across all package managers
|
||||||
|
type PackageManager interface {
|
||||||
|
Name() string
|
||||||
|
Packages() packagemap
|
||||||
|
PackageInstalled(*Package) (bool, error)
|
||||||
|
PackageAvailable(*Package) (bool, error)
|
||||||
|
InstallCommand(*Package) string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Dependancy represents a system package that we require
|
||||||
|
type Dependancy struct {
|
||||||
|
Name string
|
||||||
|
PackageName string
|
||||||
|
Installed bool
|
||||||
|
InstallCommand string
|
||||||
|
Version string
|
||||||
|
Optional bool
|
||||||
|
External bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// DependencyList is a list of Dependency instances
|
||||||
|
type DependencyList []*Dependancy
|
||||||
|
|
||||||
|
|
||||||
|
// InstallAllRequiredCommand returns the command you need to use to install all required dependencies
|
||||||
|
func (d DependencyList) InstallAllRequiredCommand() string {
|
||||||
|
|
||||||
|
result := ""
|
||||||
|
for _, dependency := range d {
|
||||||
|
if dependency.PackageName != "" {
|
||||||
|
if !dependency.Installed && !dependency.Optional {
|
||||||
|
if result == "" {
|
||||||
|
result = dependency.InstallCommand
|
||||||
|
} else {
|
||||||
|
result += " " + dependency.PackageName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstallAllOptionalCommand returns the command you need to use to install all optional dependencies
|
||||||
|
func (d DependencyList) InstallAllOptionalCommand() string {
|
||||||
|
|
||||||
|
result := ""
|
||||||
|
for _, dependency := range d {
|
||||||
|
if dependency.PackageName != "" {
|
||||||
|
if !dependency.Installed && dependency.Optional {
|
||||||
|
if result == "" {
|
||||||
|
result = dependency.InstallCommand
|
||||||
|
} else {
|
||||||
|
result += " " + dependency.PackageName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
8
v2/internal/system/system_darwin.go
Normal file
8
v2/internal/system/system_darwin.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package system
|
||||||
|
|
||||||
|
func (i *Info) discover() error {
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -2,14 +2,20 @@
|
|||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import "github.com/wailsapp/wails/v2/internal/system/operatingsystem"
|
||||||
"fmt"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (i *Info) discover() {
|
func (i *Info) discover() error {
|
||||||
dll := syscall.MustLoadDLL("kernel32.dll")
|
|
||||||
p := dll.MustFindProc("GetVersion")
|
var err error
|
||||||
v, _, _ := p.Call()
|
osinfo, err := operatingsystem.Info()
|
||||||
fmt.Printf("Windows version %d.%d (Build %d)\n", byte(v), uint8(v>>8), uint16(v>>16))
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.OS = osinfo
|
||||||
|
|
||||||
|
// dll := syscall.MustLoadDLL("kernel32.dll")
|
||||||
|
// p := dll.MustFindProc("GetVersion")
|
||||||
|
// v, _, _ := p.Call()
|
||||||
|
// fmt.Printf("Windows version %d.%d (Build %d)\n", byte(v), uint8(v>>8), uint16(v>>16))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
27
v2/internal/templates/ides/vscode/launch.json.tmpl
Normal file
27
v2/internal/templates/ides/vscode/launch.json.tmpl
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Wails: Debug {{.ProjectName}} (Desktop)",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "exec",
|
||||||
|
"program": "${workspaceFolder}/{{.PathToDesktopBinary}}",
|
||||||
|
"preLaunchTask": "build_desktop",
|
||||||
|
"cwd": "",
|
||||||
|
"env": {},
|
||||||
|
"args": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Wails: Debug {{.ProjectName}} (Server)",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "exec",
|
||||||
|
"program": "${workspaceFolder}/{{.PathToServerBinary}}",
|
||||||
|
"preLaunchTask": "build_server",
|
||||||
|
"cwd": "",
|
||||||
|
"env": {},
|
||||||
|
"args": []
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
23
v2/internal/templates/ides/vscode/tasks.json.tmpl
Normal file
23
v2/internal/templates/ides/vscode/tasks.json.tmpl
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "build_desktop",
|
||||||
|
"type": "shell",
|
||||||
|
"options": {
|
||||||
|
"cwd": "{{.TargetDir}}"
|
||||||
|
},
|
||||||
|
"command": "wails build"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "build_server",
|
||||||
|
"type": "shell",
|
||||||
|
"options": {
|
||||||
|
"cwd": "{{.TargetDir}}"
|
||||||
|
},
|
||||||
|
"command": "wails build -t server"
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
@@ -6,13 +6,14 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/leaanthony/gosod"
|
"github.com/leaanthony/gosod"
|
||||||
"github.com/leaanthony/slicer"
|
"github.com/leaanthony/slicer"
|
||||||
"github.com/olekukonko/tablewriter"
|
"github.com/olekukonko/tablewriter"
|
||||||
"github.com/wailsapp/wails/v2/internal/fs"
|
"github.com/wailsapp/wails/v2/internal/fs"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cahce for the templates
|
// Cahce for the templates
|
||||||
@@ -31,11 +32,14 @@ type Data struct {
|
|||||||
|
|
||||||
// Options for installing a template
|
// Options for installing a template
|
||||||
type Options struct {
|
type Options struct {
|
||||||
ProjectName string
|
ProjectName string
|
||||||
TemplateName string
|
TemplateName string
|
||||||
BinaryName string
|
BinaryName string
|
||||||
TargetDir string
|
TargetDir string
|
||||||
Logger *logger.Logger
|
Logger *clilogger.CLILogger
|
||||||
|
GenerateVSCode bool
|
||||||
|
PathToDesktopBinary string
|
||||||
|
PathToServerBinary string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Template holds data relating to a template
|
// Template holds data relating to a template
|
||||||
@@ -162,9 +166,24 @@ func Install(options *Options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Did the user want to install in current directory?
|
// Did the user want to install in current directory?
|
||||||
if options.TargetDir == "." {
|
if options.TargetDir == "" {
|
||||||
// Yes - use cwd
|
|
||||||
options.TargetDir = cwd
|
// If the current directory is empty, use it
|
||||||
|
isEmpty, err := fs.DirIsEmpty(cwd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if isEmpty {
|
||||||
|
// Yes - use cwd
|
||||||
|
options.TargetDir = cwd
|
||||||
|
} else {
|
||||||
|
options.TargetDir = filepath.Join(cwd, options.ProjectName)
|
||||||
|
if fs.DirExists(options.TargetDir) {
|
||||||
|
return fmt.Errorf("cannot create project directory. Dir exists: %s", options.TargetDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Get the absolute path of the given directory
|
// Get the absolute path of the given directory
|
||||||
targetDir, err := filepath.Abs(filepath.Join(cwd, options.TargetDir))
|
targetDir, err := filepath.Abs(filepath.Join(cwd, options.TargetDir))
|
||||||
@@ -213,35 +232,74 @@ func Install(options *Options) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the directory name
|
err = generateIDEFiles(options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OutputList prints the list of available tempaltes to the given logger
|
// OutputList prints the list of available tempaltes to the given logger
|
||||||
func OutputList(logger *logger.Logger) error {
|
func OutputList(logger *clilogger.CLILogger) error {
|
||||||
templates, err := List()
|
templates, err := List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, writer := range logger.Writers() {
|
table := tablewriter.NewWriter(logger.Writer)
|
||||||
table := tablewriter.NewWriter(writer)
|
table.SetHeader([]string{"Template", "Short Name", "Description"})
|
||||||
table.SetHeader([]string{"Template", "Short Name", "Description"})
|
table.SetAutoWrapText(false)
|
||||||
table.SetAutoWrapText(false)
|
table.SetAutoFormatHeaders(true)
|
||||||
table.SetAutoFormatHeaders(true)
|
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||||
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
table.SetAlignment(tablewriter.ALIGN_LEFT)
|
||||||
table.SetAlignment(tablewriter.ALIGN_LEFT)
|
table.SetCenterSeparator("")
|
||||||
table.SetCenterSeparator("")
|
table.SetColumnSeparator("")
|
||||||
table.SetColumnSeparator("")
|
table.SetRowSeparator("")
|
||||||
table.SetRowSeparator("")
|
table.SetHeaderLine(false)
|
||||||
table.SetHeaderLine(false)
|
table.SetBorder(false)
|
||||||
table.SetBorder(false)
|
table.SetTablePadding("\t") // pad with tabs
|
||||||
table.SetTablePadding("\t") // pad with tabs
|
table.SetNoWhiteSpace(true)
|
||||||
table.SetNoWhiteSpace(true)
|
for _, template := range templates {
|
||||||
for _, template := range templates {
|
table.Append([]string{template.Name, template.ShortName, template.Description})
|
||||||
table.Append([]string{template.Name, template.ShortName, template.Description})
|
|
||||||
}
|
|
||||||
table.Render()
|
|
||||||
}
|
}
|
||||||
|
table.Render()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateIDEFiles(options *Options) error {
|
||||||
|
|
||||||
|
if options.GenerateVSCode {
|
||||||
|
return generateVSCodeFiles(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateVSCodeFiles(options *Options) error {
|
||||||
|
|
||||||
|
targetDir := filepath.Join(options.TargetDir, ".vscode")
|
||||||
|
sourceDir := fs.RelativePath(filepath.Join("./ides/vscode"))
|
||||||
|
|
||||||
|
// Use Gosod to install the template
|
||||||
|
installer, err := gosod.TemplateDir(sourceDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
binaryName := filepath.Base(options.TargetDir)
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// yay windows
|
||||||
|
binaryName += ".exe"
|
||||||
|
}
|
||||||
|
|
||||||
|
options.PathToDesktopBinary = filepath.Join("build", runtime.GOOS, "desktop", binaryName)
|
||||||
|
options.PathToServerBinary = filepath.Join("build", runtime.GOOS, "server", binaryName)
|
||||||
|
|
||||||
|
err = installer.Extract(targetDir, options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,18 +34,8 @@ func (wc *WebClient) CallResult(message string) {
|
|||||||
wc.SendMessage("R" + message)
|
wc.SendMessage("R" + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveFileDialog is a noop in the webclient
|
// OpenDialog is a noop in the webclient
|
||||||
func (wc *WebClient) SaveFileDialog(title string) string {
|
func (wc *WebClient) OpenDialog(title string) string {
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenFileDialog is a noop in the webclient
|
|
||||||
func (wc *WebClient) OpenFileDialog(title string) string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenDirectoryDialog is a noop in the webclient
|
|
||||||
func (wc *WebClient) OpenDirectoryDialog(title string) string {
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,8 +49,7 @@ func (wc *WebClient) WindowFullscreen() {}
|
|||||||
func (wc *WebClient) WindowUnFullscreen() {}
|
func (wc *WebClient) WindowUnFullscreen() {}
|
||||||
|
|
||||||
// WindowSetColour is a noop in the webclient
|
// WindowSetColour is a noop in the webclient
|
||||||
func (wc *WebClient) WindowSetColour(colour string) bool {
|
func (wc *WebClient) WindowSetColour(colour int) {
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run processes messages from the remote webclient
|
// Run processes messages from the remote webclient
|
||||||
|
|||||||
59
v2/pkg/clilogger/clilogger.go
Normal file
59
v2/pkg/clilogger/clilogger.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package clilogger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CLILogger is used by the cli
|
||||||
|
type CLILogger struct {
|
||||||
|
Writer io.Writer
|
||||||
|
mute bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// New cli logger
|
||||||
|
func New(writer io.Writer) *CLILogger {
|
||||||
|
return &CLILogger{
|
||||||
|
Writer: writer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mute sets whether the logger should be muted
|
||||||
|
func (c *CLILogger) Mute(value bool) {
|
||||||
|
c.mute = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print works like Printf
|
||||||
|
func (c *CLILogger) Print(message string, args ...interface{}) {
|
||||||
|
if c.mute {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := fmt.Fprintf(c.Writer, message, args...)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatal("Fatal: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println works like Printf but with a line ending
|
||||||
|
func (c *CLILogger) Println(message string, args ...interface{}) {
|
||||||
|
if c.mute {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
temp := fmt.Sprintf(message, args...)
|
||||||
|
_, err := fmt.Fprintln(c.Writer, temp)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatal("Fatal: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatal prints the given message then aborts
|
||||||
|
func (c *CLILogger) Fatal(message string, args ...interface{}) {
|
||||||
|
temp := fmt.Sprintf(message, args...)
|
||||||
|
_, err := fmt.Fprintln(c.Writer, "FATAL: "+temp)
|
||||||
|
if err != nil {
|
||||||
|
println("FATAL: ", err)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
@@ -14,9 +14,9 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2/internal/assetdb"
|
"github.com/wailsapp/wails/v2/internal/assetdb"
|
||||||
"github.com/wailsapp/wails/v2/internal/fs"
|
"github.com/wailsapp/wails/v2/internal/fs"
|
||||||
"github.com/wailsapp/wails/v2/internal/html"
|
"github.com/wailsapp/wails/v2/internal/html"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/project"
|
"github.com/wailsapp/wails/v2/internal/project"
|
||||||
"github.com/wailsapp/wails/v2/internal/shell"
|
"github.com/wailsapp/wails/v2/internal/shell"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BaseBuilder is the common builder struct
|
// BaseBuilder is the common builder struct
|
||||||
@@ -305,7 +305,7 @@ func (b *BaseBuilder) NpmRunWithEnvironment(projectDir, buildTarget string, verb
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BuildFrontend executes the `npm build` command for the frontend directory
|
// BuildFrontend executes the `npm build` command for the frontend directory
|
||||||
func (b *BaseBuilder) BuildFrontend(outputLogger *logger.Logger) error {
|
func (b *BaseBuilder) BuildFrontend(outputLogger *clilogger.CLILogger) error {
|
||||||
verbose := false
|
verbose := false
|
||||||
|
|
||||||
frontendDir := filepath.Join(b.projectData.Path, "frontend")
|
frontendDir := filepath.Join(b.projectData.Path, "frontend")
|
||||||
@@ -313,10 +313,10 @@ func (b *BaseBuilder) BuildFrontend(outputLogger *logger.Logger) error {
|
|||||||
// Check there is an 'InstallCommand' provided in wails.json
|
// Check there is an 'InstallCommand' provided in wails.json
|
||||||
if b.projectData.InstallCommand == "" {
|
if b.projectData.InstallCommand == "" {
|
||||||
// No - don't install
|
// No - don't install
|
||||||
outputLogger.Writeln(" - No Install command. Skipping.")
|
outputLogger.Println(" - No Install command. Skipping.")
|
||||||
} else {
|
} else {
|
||||||
// Do install if needed
|
// Do install if needed
|
||||||
outputLogger.Writeln(" - Installing dependencies...")
|
outputLogger.Println(" - Installing dependencies...")
|
||||||
if err := b.NpmInstallUsingCommand(frontendDir, b.projectData.InstallCommand); err != nil {
|
if err := b.NpmInstallUsingCommand(frontendDir, b.projectData.InstallCommand); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -324,12 +324,12 @@ func (b *BaseBuilder) BuildFrontend(outputLogger *logger.Logger) error {
|
|||||||
|
|
||||||
// Check if there is a build command
|
// Check if there is a build command
|
||||||
if b.projectData.BuildCommand == "" {
|
if b.projectData.BuildCommand == "" {
|
||||||
outputLogger.Writeln(" - No Build command. Skipping.")
|
outputLogger.Println(" - No Build command. Skipping.")
|
||||||
// No - ignore
|
// No - ignore
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
outputLogger.Writeln(" - Compiling Frontend Project")
|
outputLogger.Println(" - Compiling Frontend Project")
|
||||||
cmd := strings.Split(b.projectData.BuildCommand, " ")
|
cmd := strings.Split(b.projectData.BuildCommand, " ")
|
||||||
stdout, stderr, err := shell.RunCommand(frontendDir, cmd[0], cmd[1:]...)
|
stdout, stderr, err := shell.RunCommand(frontendDir, cmd[0], cmd[1:]...)
|
||||||
if verbose || err != nil {
|
if verbose || err != nil {
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/leaanthony/slicer"
|
"github.com/leaanthony/slicer"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/project"
|
"github.com/wailsapp/wails/v2/internal/project"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Mode is the type used to indicate the build modes
|
// Mode is the type used to indicate the build modes
|
||||||
@@ -24,16 +25,16 @@ var modeMap = []string{"Debug", "Production"}
|
|||||||
|
|
||||||
// Options contains all the build options as well as the project data
|
// Options contains all the build options as well as the project data
|
||||||
type Options struct {
|
type Options struct {
|
||||||
LDFlags string // Optional flags to pass to linker
|
LDFlags string // Optional flags to pass to linker
|
||||||
Logger *logger.Logger // All output to the logger
|
Logger *clilogger.CLILogger // All output to the logger
|
||||||
OutputType string // EG: desktop, server....
|
OutputType string // EG: desktop, server....
|
||||||
Mode Mode // release or debug
|
Mode Mode // release or debug
|
||||||
ProjectData *project.Project // The project data
|
ProjectData *project.Project // The project data
|
||||||
Pack bool // Create a package for the app after building
|
Pack bool // Create a package for the app after building
|
||||||
Platform string // The platform to build for
|
Platform string // The platform to build for
|
||||||
Compiler string // The compiler command to use
|
Compiler string // The compiler command to use
|
||||||
IgnoreFrontend bool // Indicates if the frontend does not need building
|
IgnoreFrontend bool // Indicates if the frontend does not need building
|
||||||
OutputFile string // Override the output filename
|
OutputFile string // Override the output filename
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetModeAsString returns the current mode as a string
|
// GetModeAsString returns the current mode as a string
|
||||||
@@ -47,11 +48,6 @@ func Build(options *Options) (string, error) {
|
|||||||
// Extract logger
|
// Extract logger
|
||||||
outputLogger := options.Logger
|
outputLogger := options.Logger
|
||||||
|
|
||||||
// Create a default logger if it doesn't exist
|
|
||||||
if outputLogger == nil {
|
|
||||||
outputLogger = logger.New()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get working directory
|
// Get working directory
|
||||||
cwd, err := os.Getwd()
|
cwd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -59,7 +55,7 @@ func Build(options *Options) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check platform
|
// Check platform
|
||||||
validPlatforms := slicer.String([]string{"linux"})
|
validPlatforms := slicer.String([]string{"linux", "darwin"})
|
||||||
if !validPlatforms.Contains(options.Platform) {
|
if !validPlatforms.Contains(options.Platform) {
|
||||||
return "", fmt.Errorf("platform %s not supported", options.Platform)
|
return "", fmt.Errorf("platform %s not supported", options.Platform)
|
||||||
}
|
}
|
||||||
@@ -94,8 +90,15 @@ func Build(options *Options) (string, error) {
|
|||||||
// Initialise Builder
|
// Initialise Builder
|
||||||
builder.SetProjectData(projectData)
|
builder.SetProjectData(projectData)
|
||||||
|
|
||||||
|
// Generate Frontend JS Package
|
||||||
|
outputLogger.Println(" - Generating Backend JS Package")
|
||||||
|
// Ignore the parser report coming back
|
||||||
|
_, err = parser.GenerateWailsFrontendPackage()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
if !options.IgnoreFrontend {
|
if !options.IgnoreFrontend {
|
||||||
outputLogger.Writeln(" - Building Wails Frontend")
|
outputLogger.Println(" - Building Wails Frontend")
|
||||||
err = builder.BuildFrontend(outputLogger)
|
err = builder.BuildFrontend(outputLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -103,7 +106,7 @@ func Build(options *Options) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build the base assets
|
// Build the base assets
|
||||||
outputLogger.Writeln(" - Compiling Assets")
|
outputLogger.Println(" - Compiling Assets")
|
||||||
err = builder.BuildRuntime(options)
|
err = builder.BuildRuntime(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -114,16 +117,17 @@ func Build(options *Options) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compile the application
|
// Compile the application
|
||||||
outputLogger.Write(" - Compiling Application in " + GetModeAsString(options.Mode) + " mode...")
|
outputLogger.Print(" - Compiling Application in " + GetModeAsString(options.Mode) + " mode...")
|
||||||
err = builder.CompileProject(options)
|
err = builder.CompileProject(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
outputLogger.Writeln("done.")
|
outputLogger.Println("done.")
|
||||||
|
|
||||||
// Do we need to pack the app?
|
// Do we need to pack the app?
|
||||||
if options.Pack {
|
if options.Pack {
|
||||||
|
|
||||||
outputLogger.Writeln(" - Packaging Application")
|
outputLogger.Println(" - Packaging Application")
|
||||||
|
|
||||||
// TODO: Allow cross platform build
|
// TODO: Allow cross platform build
|
||||||
err = packageProject(options, runtime.GOOS)
|
err = packageProject(options, runtime.GOOS)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user