mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-03 06:39:30 +08:00
[v2] [broken - WIP] Major refactor of runtime in progress
This commit is contained in:
parent
b80a64b0ee
commit
f02c140709
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||||
"github.com/wailsapp/wails/v2/internal/runtime"
|
|
||||||
"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"
|
||||||
@ -46,10 +45,6 @@ type App struct {
|
|||||||
// This is our binding DB
|
// This is our binding DB
|
||||||
bindings *binding.Bindings
|
bindings *binding.Bindings
|
||||||
|
|
||||||
// Application Stores
|
|
||||||
loglevelStore *runtime.Store
|
|
||||||
appconfigStore *runtime.Store
|
|
||||||
|
|
||||||
// Startup/Shutdown
|
// Startup/Shutdown
|
||||||
startupCallback func(ctx context.Context)
|
startupCallback func(ctx context.Context)
|
||||||
shutdownCallback func()
|
shutdownCallback func()
|
||||||
@ -145,12 +140,8 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Application Stores
|
|
||||||
a.loglevelStore = a.runtime.GoRuntime().Store.New("wails:loglevel", a.options.LogLevel)
|
|
||||||
a.appconfigStore = a.runtime.GoRuntime().Store.New("wails:appconfig", a.options)
|
|
||||||
|
|
||||||
// Start the logging subsystem
|
// Start the logging subsystem
|
||||||
log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore)
|
log, err := subsystem.NewLog(a.servicebus, a.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -207,7 +198,7 @@ func (a *App) Run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the call subsystem
|
// Start the call subsystem
|
||||||
callSubsystem, err := subsystem.NewCall(ctx, a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
|
callSubsystem, err := subsystem.NewCall(ctx, a.servicebus, a.logger, a.bindings.DB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ 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/messagedispatcher"
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||||
"github.com/wailsapp/wails/v2/internal/runtime"
|
|
||||||
"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"
|
||||||
@ -185,7 +184,7 @@ func (a *App) Run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the call subsystem
|
// Start the call subsystem
|
||||||
callSubsystem, err := subsystem.NewCall(ctx, a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
|
callSubsystem, err := subsystem.NewCall(ctx, a.servicebus, a.logger, a.bindings.DB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
@ -12,7 +13,6 @@ 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/messagedispatcher"
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||||
"github.com/wailsapp/wails/v2/internal/runtime"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
"github.com/wailsapp/wails/v2/internal/subsystem"
|
"github.com/wailsapp/wails/v2/internal/subsystem"
|
||||||
"github.com/wailsapp/wails/v2/internal/webserver"
|
"github.com/wailsapp/wails/v2/internal/webserver"
|
||||||
@ -26,7 +26,6 @@ type App struct {
|
|||||||
call *subsystem.Call
|
call *subsystem.Call
|
||||||
event *subsystem.Event
|
event *subsystem.Event
|
||||||
log *subsystem.Log
|
log *subsystem.Log
|
||||||
runtime *subsystem.Runtime
|
|
||||||
|
|
||||||
options *options.App
|
options *options.App
|
||||||
|
|
||||||
@ -38,12 +37,8 @@ type App struct {
|
|||||||
|
|
||||||
debug bool
|
debug bool
|
||||||
|
|
||||||
// Application Stores
|
|
||||||
loglevelStore *runtime.Store
|
|
||||||
appconfigStore *runtime.Store
|
|
||||||
|
|
||||||
// Startup/Shutdown
|
// Startup/Shutdown
|
||||||
startupCallback func(*runtime.Runtime)
|
startupCallback func(ctx context.Context)
|
||||||
shutdownCallback func()
|
shutdownCallback func()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,19 +104,15 @@ func (a *App) Run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the runtime
|
// Start the runtime
|
||||||
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger, a.startupCallback, a.shutdownCallback)
|
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger, a.startupCallback)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
a.runtime = runtime
|
a.runtime = runtime
|
||||||
a.runtime.Start()
|
a.runtime.Start()
|
||||||
|
|
||||||
// Application Stores
|
|
||||||
a.loglevelStore = a.runtime.GoRuntime().Store.New("wails:loglevel", a.options.LogLevel)
|
|
||||||
a.appconfigStore = a.runtime.GoRuntime().Store.New("wails:appconfig", a.options)
|
|
||||||
|
|
||||||
a.servicebus.Start()
|
a.servicebus.Start()
|
||||||
log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore)
|
log, err := subsystem.NewLog(a.servicebus, a.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -135,7 +126,7 @@ func (a *App) Run() error {
|
|||||||
a.dispatcher.Start()
|
a.dispatcher.Start()
|
||||||
|
|
||||||
// Start the binding subsystem
|
// Start the binding subsystem
|
||||||
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, runtime.GoRuntime())
|
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
package runtime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os/exec"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Browser defines all browser related operations
|
|
||||||
type Browser interface {
|
|
||||||
Open(target string) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type browser struct{}
|
|
||||||
|
|
||||||
// Open a url / file using the system default application
|
|
||||||
// Credit: https://gist.github.com/hyg/9c4afcd91fe24316cbf0
|
|
||||||
func (b *browser) Open(target string) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "linux":
|
|
||||||
err = exec.Command("xdg-open", target).Start()
|
|
||||||
case "windows":
|
|
||||||
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", target).Start()
|
|
||||||
case "darwin":
|
|
||||||
err = exec.Command("open", target).Start()
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("unsupported platform")
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBrowser() *browser {
|
|
||||||
return &browser{}
|
|
||||||
}
|
|
@ -1,172 +0,0 @@
|
|||||||
package runtime
|
|
||||||
|
|
||||||
//
|
|
||||||
//import (
|
|
||||||
// "fmt"
|
|
||||||
// "github.com/wailsapp/wails/v2/internal/crypto"
|
|
||||||
// "github.com/wailsapp/wails/v2/internal/servicebus"
|
|
||||||
// d "github.com/wailsapp/wails/v2/pkg/runtime/dialog"
|
|
||||||
//)
|
|
||||||
//
|
|
||||||
//// Dialog defines all Dialog related operations
|
|
||||||
//type Dialog interface {
|
|
||||||
// OpenFile(options d.OpenDialogOptions) (string, error)
|
|
||||||
// OpenMultipleFiles(options d.OpenDialogOptions) ([]string, error)
|
|
||||||
// OpenDirectory(options d.OpenDialogOptions) (string, error)
|
|
||||||
// SaveFile(options d.SaveDialogOptions) (string, error)
|
|
||||||
// Message(options d.MessageDialogOptions) (string, error)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// 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
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// OpenDirectory prompts the user to select a directory
|
|
||||||
//func (r *dialog) OpenDirectory(dialogOptions d.OpenDialogOptions) (string, error) {
|
|
||||||
//
|
|
||||||
// // Create unique dialog callback
|
|
||||||
// uniqueCallback := crypto.RandomID()
|
|
||||||
//
|
|
||||||
// // Subscribe to the respose channel
|
|
||||||
// responseTopic := "dialog:opendirectoryselected:" + uniqueCallback
|
|
||||||
// dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
|
|
||||||
// if err != nil {
|
|
||||||
// return "", fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// message := "dialog:select:directory:" + uniqueCallback
|
|
||||||
// r.bus.Publish(message, dialogOptions)
|
|
||||||
//
|
|
||||||
// // Wait for result
|
|
||||||
// var result = <-dialogResponseChannel
|
|
||||||
//
|
|
||||||
// // Delete subscription to response topic
|
|
||||||
// r.bus.UnSubscribe(responseTopic)
|
|
||||||
//
|
|
||||||
// return result.Data().(string), nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// OpenFile prompts the user to select a file
|
|
||||||
//func (r *dialog) OpenFile(dialogOptions d.OpenDialogOptions) (string, error) {
|
|
||||||
//
|
|
||||||
// // 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 {
|
|
||||||
// return "", fmt.Errorf("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 = <-dialogResponseChannel
|
|
||||||
//
|
|
||||||
// // Delete subscription to response topic
|
|
||||||
// r.bus.UnSubscribe(responseTopic)
|
|
||||||
//
|
|
||||||
// return result.Data().(string), nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// OpenMultipleFiles prompts the user to select a file
|
|
||||||
//func (r *dialog) OpenMultipleFiles(dialogOptions d.OpenDialogOptions) ([]string, error) {
|
|
||||||
//
|
|
||||||
// // Create unique dialog callback
|
|
||||||
// uniqueCallback := crypto.RandomID()
|
|
||||||
//
|
|
||||||
// // Subscribe to the respose channel
|
|
||||||
// responseTopic := "dialog:openmultipleselected:" + uniqueCallback
|
|
||||||
// dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// message := "dialog:select:openmultiple:" + uniqueCallback
|
|
||||||
// r.bus.Publish(message, dialogOptions)
|
|
||||||
//
|
|
||||||
// // Wait for result
|
|
||||||
// var result = <-dialogResponseChannel
|
|
||||||
//
|
|
||||||
// // Delete subscription to response topic
|
|
||||||
// r.bus.UnSubscribe(responseTopic)
|
|
||||||
//
|
|
||||||
// return result.Data().([]string), nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// SaveFile prompts the user to select a file
|
|
||||||
//func (r *dialog) SaveFile(dialogOptions d.SaveDialogOptions) (string, error) {
|
|
||||||
//
|
|
||||||
// // 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 {
|
|
||||||
// return "", fmt.Errorf("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 = <-dialogResponseChannel
|
|
||||||
//
|
|
||||||
// // Delete subscription to response topic
|
|
||||||
// r.bus.UnSubscribe(responseTopic)
|
|
||||||
//
|
|
||||||
// return result.Data().(string), nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// Message show a message to the user
|
|
||||||
//func (r *dialog) Message(dialogOptions d.MessageDialogOptions) (string, error) {
|
|
||||||
//
|
|
||||||
// // Create unique dialog callback
|
|
||||||
// uniqueCallback := crypto.RandomID()
|
|
||||||
//
|
|
||||||
// // Subscribe to the respose channel
|
|
||||||
// responseTopic := "dialog:messageselected:" + uniqueCallback
|
|
||||||
// dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
|
|
||||||
// if err != nil {
|
|
||||||
// return "", fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// message := "dialog:select:message:" + uniqueCallback
|
|
||||||
// r.bus.Publish(message, dialogOptions)
|
|
||||||
//
|
|
||||||
// // Wait for result
|
|
||||||
// var result = <-dialogResponseChannel
|
|
||||||
//
|
|
||||||
// // Delete subscription to response topic
|
|
||||||
// r.bus.UnSubscribe(responseTopic)
|
|
||||||
//
|
|
||||||
// return result.Data().(string), nil
|
|
||||||
//}
|
|
@ -1,86 +0,0 @@
|
|||||||
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{})
|
|
||||||
OnThemeChange(callback func(darkMode bool))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnThemeChange allows you to register callbacks when the system theme changes
|
|
||||||
// from light or dark.
|
|
||||||
func (r *event) OnThemeChange(callback func(darkMode bool)) {
|
|
||||||
r.On("wails:system:themechange", func(data ...interface{}) {
|
|
||||||
if len(data) != 1 {
|
|
||||||
// TODO: Log error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
darkMode, ok := data[0].(bool)
|
|
||||||
if !ok {
|
|
||||||
// TODO: Log error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
callback(darkMode)
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
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,46 +0,0 @@
|
|||||||
package runtime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Menu defines all Menu related operations
|
|
||||||
type Menu interface {
|
|
||||||
UpdateApplicationMenu()
|
|
||||||
UpdateContextMenu(contextMenu *menu.ContextMenu)
|
|
||||||
SetTrayMenu(trayMenu *menu.TrayMenu)
|
|
||||||
DeleteTrayMenu(trayMenu *menu.TrayMenu)
|
|
||||||
UpdateTrayMenuLabel(trayMenu *menu.TrayMenu)
|
|
||||||
}
|
|
||||||
|
|
||||||
type menuRuntime struct {
|
|
||||||
bus *servicebus.ServiceBus
|
|
||||||
}
|
|
||||||
|
|
||||||
// newMenu creates a new Menu struct
|
|
||||||
func newMenu(bus *servicebus.ServiceBus) Menu {
|
|
||||||
return &menuRuntime{
|
|
||||||
bus: bus,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *menuRuntime) UpdateApplicationMenu() {
|
|
||||||
m.bus.Publish("menu:updateappmenu", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *menuRuntime) UpdateContextMenu(contextMenu *menu.ContextMenu) {
|
|
||||||
m.bus.Publish("menu:updatecontextmenu", contextMenu)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *menuRuntime) SetTrayMenu(trayMenu *menu.TrayMenu) {
|
|
||||||
m.bus.Publish("menu:settraymenu", trayMenu)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *menuRuntime) UpdateTrayMenuLabel(trayMenu *menu.TrayMenu) {
|
|
||||||
m.bus.Publish("menu:updatetraymenulabel", trayMenu)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *menuRuntime) DeleteTrayMenu(trayMenu *menu.TrayMenu) {
|
|
||||||
m.bus.Publish("menu:deletetraymenu", trayMenu)
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package runtime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Runtime is a means for the user to interact with the application at runtime
|
|
||||||
type Runtime struct {
|
|
||||||
Browser Browser
|
|
||||||
Events Events
|
|
||||||
Window Window
|
|
||||||
System System
|
|
||||||
Menu Menu
|
|
||||||
Store *StoreProvider
|
|
||||||
Log Log
|
|
||||||
bus *servicebus.ServiceBus
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new runtime
|
|
||||||
func New(serviceBus *servicebus.ServiceBus) *Runtime {
|
|
||||||
result := &Runtime{
|
|
||||||
Browser: newBrowser(),
|
|
||||||
Events: newEvents(serviceBus),
|
|
||||||
Window: newWindow(serviceBus),
|
|
||||||
System: newSystem(serviceBus),
|
|
||||||
Menu: newMenu(serviceBus),
|
|
||||||
Log: newLog(serviceBus),
|
|
||||||
bus: serviceBus,
|
|
||||||
}
|
|
||||||
result.Store = newStore(result)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quit the application
|
|
||||||
func (r *Runtime) Quit() {
|
|
||||||
// Start shutdown of Wails
|
|
||||||
r.bus.Publish("quit", "runtime.Quit()")
|
|
||||||
}
|
|
@ -1,367 +0,0 @@
|
|||||||
// 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"
|
|
||||||
golog "log"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/deepcopy"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
|
|
||||||
if defaultValue == nil {
|
|
||||||
golog.Fatal("Cannot initialise a store with nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
result := Store{
|
|
||||||
name: name,
|
|
||||||
runtime: p.runtime,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup the sync listener
|
|
||||||
result.setupListener()
|
|
||||||
|
|
||||||
result.Set(defaultValue)
|
|
||||||
|
|
||||||
return &result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) lock() {
|
|
||||||
s.mux.Lock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) unlock() {
|
|
||||||
s.mux.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.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.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()
|
|
||||||
})
|
|
||||||
|
|
||||||
// Listen for resync events
|
|
||||||
s.runtime.Events.On("wails:sync:store:resync:"+s.name, func(data ...interface{}) {
|
|
||||||
// Resetting the curent data will resync
|
|
||||||
s.resync()
|
|
||||||
})
|
|
||||||
|
|
||||||
// Do initial resync
|
|
||||||
s.resync()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) resync() {
|
|
||||||
|
|
||||||
// Lock
|
|
||||||
s.lock()
|
|
||||||
defer s.unlock()
|
|
||||||
|
|
||||||
var result string
|
|
||||||
|
|
||||||
if s.data.IsValid() {
|
|
||||||
rawdata, err := json.Marshal(s.data.Interface())
|
|
||||||
if err != nil {
|
|
||||||
if s.errorHandler != nil {
|
|
||||||
s.errorHandler(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = string(rawdata)
|
|
||||||
} else {
|
|
||||||
result = "{}"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit event to front end
|
|
||||||
s.runtime.Events.Emit("wails:sync:store:updatedbybackend:"+s.name, result)
|
|
||||||
|
|
||||||
// Notify subscribers
|
|
||||||
s.notify()
|
|
||||||
}
|
|
||||||
|
|
||||||
// notify the listeners of the current data state
|
|
||||||
func (s *Store) notify() {
|
|
||||||
|
|
||||||
// Execute callbacks
|
|
||||||
for _, callback := range s.callbacks {
|
|
||||||
|
|
||||||
// Build args
|
|
||||||
s.lock()
|
|
||||||
args := []reflect.Value{s.data}
|
|
||||||
s.unlock()
|
|
||||||
|
|
||||||
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 {
|
|
||||||
|
|
||||||
if data == nil {
|
|
||||||
return fmt.Errorf("cannot set store to nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
s.lock()
|
|
||||||
|
|
||||||
dataCopy := deepcopy.Copy(data)
|
|
||||||
|
|
||||||
if dataCopy != nil {
|
|
||||||
inType := reflect.TypeOf(dataCopy)
|
|
||||||
|
|
||||||
if inType != s.dataType && s.data.IsValid() {
|
|
||||||
s.unlock()
|
|
||||||
return fmt.Errorf("invalid data given in Store.Set(). Expected %s, got %s", s.dataType.String(), inType.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.dataType == nil {
|
|
||||||
s.dataType = reflect.TypeOf(dataCopy)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save data
|
|
||||||
s.data = reflect.ValueOf(dataCopy)
|
|
||||||
|
|
||||||
s.unlock()
|
|
||||||
|
|
||||||
// Resync with subscribers
|
|
||||||
s.resync()
|
|
||||||
|
|
||||||
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.lock()
|
|
||||||
s.callbacks = append(s.callbacks, callbackFunc)
|
|
||||||
s.unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
s.lock()
|
|
||||||
args := []reflect.Value{s.data}
|
|
||||||
s.unlock()
|
|
||||||
|
|
||||||
// Make call
|
|
||||||
results := reflect.ValueOf(updater).Call(args)
|
|
||||||
|
|
||||||
// We will only have 1 result. Set the store to it
|
|
||||||
s.Set(results[0].Interface())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the value of the data that's kept in the current state / Store
|
|
||||||
func (s *Store) Get() interface{} {
|
|
||||||
s.lock()
|
|
||||||
defer s.unlock()
|
|
||||||
|
|
||||||
if !s.data.IsValid() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.data.Interface()
|
|
||||||
}
|
|
@ -1,165 +0,0 @@
|
|||||||
package runtime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"math/rand"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
internallogger "github.com/wailsapp/wails/v2/internal/logger"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
|
||||||
|
|
||||||
is2 "github.com/matryer/is"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestStoreProvider_NewWithNilDefault(t *testing.T) {
|
|
||||||
is := is2.New(t)
|
|
||||||
|
|
||||||
defaultLogger := logger.NewDefaultLogger()
|
|
||||||
testLogger := internallogger.New(defaultLogger)
|
|
||||||
//testLogger.SetLogLevel(logger.TRACE)
|
|
||||||
serviceBus := servicebus.New(testLogger)
|
|
||||||
err := serviceBus.Start()
|
|
||||||
is.NoErr(err)
|
|
||||||
defer serviceBus.Stop()
|
|
||||||
|
|
||||||
testRuntime := New(serviceBus)
|
|
||||||
storeProvider := newStore(testRuntime)
|
|
||||||
|
|
||||||
testStore := storeProvider.New("test", 0)
|
|
||||||
|
|
||||||
// You should be able to write a new value into a
|
|
||||||
// store initialised with nil
|
|
||||||
err = testStore.Set(100)
|
|
||||||
is.NoErr(err)
|
|
||||||
|
|
||||||
// You shouldn't be able to write different types to the
|
|
||||||
// store
|
|
||||||
err = testStore.Set(false)
|
|
||||||
is.True(err != nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStoreProvider_NewWithScalarDefault(t *testing.T) {
|
|
||||||
is := is2.New(t)
|
|
||||||
|
|
||||||
defaultLogger := logger.NewDefaultLogger()
|
|
||||||
testLogger := internallogger.New(defaultLogger)
|
|
||||||
//testLogger.SetLogLevel(logger.TRACE)
|
|
||||||
serviceBus := servicebus.New(testLogger)
|
|
||||||
err := serviceBus.Start()
|
|
||||||
is.NoErr(err)
|
|
||||||
defer serviceBus.Stop()
|
|
||||||
|
|
||||||
testRuntime := New(serviceBus)
|
|
||||||
storeProvider := newStore(testRuntime)
|
|
||||||
testStore := storeProvider.New("test", 100)
|
|
||||||
value := testStore.Get()
|
|
||||||
is.Equal(value, 100)
|
|
||||||
testStore.resync()
|
|
||||||
value = testStore.Get()
|
|
||||||
is.Equal(value, 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStoreProvider_NewWithStructDefault(t *testing.T) {
|
|
||||||
is := is2.New(t)
|
|
||||||
|
|
||||||
defaultLogger := logger.NewDefaultLogger()
|
|
||||||
testLogger := internallogger.New(defaultLogger)
|
|
||||||
//testLogger.SetLogLevel(logger.TRACE)
|
|
||||||
serviceBus := servicebus.New(testLogger)
|
|
||||||
err := serviceBus.Start()
|
|
||||||
is.NoErr(err)
|
|
||||||
defer serviceBus.Stop()
|
|
||||||
|
|
||||||
testRuntime := New(serviceBus)
|
|
||||||
storeProvider := newStore(testRuntime)
|
|
||||||
|
|
||||||
type TestValue struct {
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
testValue := &TestValue{
|
|
||||||
Name: "hi",
|
|
||||||
}
|
|
||||||
|
|
||||||
testStore := storeProvider.New("test", testValue)
|
|
||||||
|
|
||||||
err = testStore.Set(testValue)
|
|
||||||
is.NoErr(err)
|
|
||||||
testStore.resync()
|
|
||||||
value := testStore.Get()
|
|
||||||
is.Equal(value, testValue)
|
|
||||||
is.Equal(value.(*TestValue).Name, "hi")
|
|
||||||
|
|
||||||
testValue = &TestValue{
|
|
||||||
Name: "there",
|
|
||||||
}
|
|
||||||
err = testStore.Set(testValue)
|
|
||||||
is.NoErr(err)
|
|
||||||
testStore.resync()
|
|
||||||
value = testStore.Get()
|
|
||||||
is.Equal(value, testValue)
|
|
||||||
is.Equal(value.(*TestValue).Name, "there")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStoreProvider_RapidReadWrite(t *testing.T) {
|
|
||||||
is := is2.New(t)
|
|
||||||
|
|
||||||
defaultLogger := logger.NewDefaultLogger()
|
|
||||||
testLogger := internallogger.New(defaultLogger)
|
|
||||||
//testLogger.SetLogLevel(logger.TRACE)
|
|
||||||
serviceBus := servicebus.New(testLogger)
|
|
||||||
err := serviceBus.Start()
|
|
||||||
is.NoErr(err)
|
|
||||||
defer serviceBus.Stop()
|
|
||||||
|
|
||||||
testRuntime := New(serviceBus)
|
|
||||||
storeProvider := newStore(testRuntime)
|
|
||||||
|
|
||||||
testStore := storeProvider.New("test", 1)
|
|
||||||
|
|
||||||
ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
readers := 100
|
|
||||||
writers := 100
|
|
||||||
wg.Add(readers + writers)
|
|
||||||
// Setup readers
|
|
||||||
go func(testStore *Store, ctx context.Context) {
|
|
||||||
for readerCount := 0; readerCount < readers; readerCount++ {
|
|
||||||
go func(store *Store, ctx context.Context, id int) {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
wg.Done()
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
store.Get()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}(testStore, ctx, readerCount)
|
|
||||||
}
|
|
||||||
}(testStore, ctx)
|
|
||||||
|
|
||||||
// Setup writers
|
|
||||||
go func(testStore *Store, ctx context.Context) {
|
|
||||||
for writerCount := 0; writerCount < writers; writerCount++ {
|
|
||||||
go func(store *Store, ctx context.Context, id int) {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
wg.Done()
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
err := store.Set(rand.Int())
|
|
||||||
is.NoErr(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}(testStore, ctx, writerCount)
|
|
||||||
}
|
|
||||||
}(testStore, ctx)
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
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())
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
// +build !desktop,!server
|
|
||||||
|
|
||||||
package runtime
|
|
||||||
|
|
||||||
// AppType returns the application type, EG: desktop
|
|
||||||
func (r *system) AppType() string {
|
|
||||||
return "default"
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
// +build desktop,!server
|
|
||||||
|
|
||||||
package runtime
|
|
||||||
|
|
||||||
// AppType returns the application type, EG: desktop
|
|
||||||
func (r *system) AppType() string {
|
|
||||||
return "desktop"
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
// +build server
|
|
||||||
|
|
||||||
package runtime
|
|
||||||
|
|
||||||
// AppType returns the application type, EG: desktop
|
|
||||||
func (r *system) AppType() string {
|
|
||||||
return "server"
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
package runtime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Window defines all Window related operations
|
|
||||||
type Window interface {
|
|
||||||
Close()
|
|
||||||
Center()
|
|
||||||
Show()
|
|
||||||
Hide()
|
|
||||||
Maximise()
|
|
||||||
Unmaximise()
|
|
||||||
Minimise()
|
|
||||||
Unminimise()
|
|
||||||
SetTitle(title string)
|
|
||||||
SetSize(width int, height int)
|
|
||||||
SetMinSize(width int, height int)
|
|
||||||
SetMaxSize(width int, height int)
|
|
||||||
SetPosition(x int, y int)
|
|
||||||
Fullscreen()
|
|
||||||
UnFullscreen()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Window exposes the Windows interface
|
|
||||||
type window struct {
|
|
||||||
bus *servicebus.ServiceBus
|
|
||||||
}
|
|
||||||
|
|
||||||
// newWindow creates a new window struct
|
|
||||||
func newWindow(bus *servicebus.ServiceBus) Window {
|
|
||||||
return &window{
|
|
||||||
bus: bus,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the Window
|
|
||||||
// DISCUSSION:
|
|
||||||
// Should we even be doing this now we have a server build?
|
|
||||||
// Runtime.Quit() makes more sense than closing a window...
|
|
||||||
func (w *window) Close() {
|
|
||||||
w.bus.Publish("quit", "runtime.Close()")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTitle sets the title of the window
|
|
||||||
func (w *window) SetTitle(title string) {
|
|
||||||
w.bus.Publish("window:settitle", title)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fullscreen makes the window fullscreen
|
|
||||||
func (w *window) Fullscreen() {
|
|
||||||
w.bus.Publish("window:fullscreen", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnFullscreen makes the window UnFullscreen
|
|
||||||
func (w *window) UnFullscreen() {
|
|
||||||
w.bus.Publish("window:unfullscreen", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Center the window on the current screen
|
|
||||||
func (w *window) Center() {
|
|
||||||
w.bus.Publish("window:center", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show shows the window if hidden
|
|
||||||
func (w *window) Show() {
|
|
||||||
w.bus.Publish("window:show", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide the window
|
|
||||||
func (w *window) Hide() {
|
|
||||||
w.bus.Publish("window:hide", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSize sets the size of the window
|
|
||||||
func (w *window) SetSize(width int, height int) {
|
|
||||||
message := fmt.Sprintf("window:size:%d:%d", width, height)
|
|
||||||
w.bus.Publish(message, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSize sets the size of the window
|
|
||||||
func (w *window) SetMinSize(width int, height int) {
|
|
||||||
message := fmt.Sprintf("window:minsize:%d:%d", width, height)
|
|
||||||
w.bus.Publish(message, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSize sets the size of the window
|
|
||||||
func (w *window) SetMaxSize(width int, height int) {
|
|
||||||
message := fmt.Sprintf("window:maxsize:%d:%d", width, height)
|
|
||||||
w.bus.Publish(message, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPosition sets the position of the window
|
|
||||||
func (w *window) SetPosition(x int, y int) {
|
|
||||||
message := fmt.Sprintf("window:position:%d:%d", x, y)
|
|
||||||
w.bus.Publish(message, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maximise the window
|
|
||||||
func (w *window) Maximise() {
|
|
||||||
w.bus.Publish("window:maximise", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmaximise the window
|
|
||||||
func (w *window) Unmaximise() {
|
|
||||||
w.bus.Publish("window:unmaximise", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Minimise the window
|
|
||||||
func (w *window) Minimise() {
|
|
||||||
w.bus.Publish("window:minimise", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unminimise the window
|
|
||||||
func (w *window) Unminimise() {
|
|
||||||
w.bus.Publish("window:unminimise", "")
|
|
||||||
}
|
|
17
v2/internal/servicebus/extract.go
Normal file
17
v2/internal/servicebus/extract.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package servicebus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExtractBus(ctx context.Context) *ServiceBus {
|
||||||
|
bus := ctx.Value("bus")
|
||||||
|
if bus == nil {
|
||||||
|
pc, _, _, _ := runtime.Caller(1)
|
||||||
|
funcName := runtime.FuncForPC(pc).Name()
|
||||||
|
log.Fatalf("cannot call '%s': Application not initialised", funcName)
|
||||||
|
}
|
||||||
|
return bus.(*ServiceBus)
|
||||||
|
}
|
@ -3,7 +3,6 @@ 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"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,13 +18,10 @@ type Binding struct {
|
|||||||
|
|
||||||
// logger
|
// logger
|
||||||
logger logger.CustomLogger
|
logger logger.CustomLogger
|
||||||
|
|
||||||
// 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 *runtime.Runtime) (*Binding, error) {
|
func NewBinding(bus *servicebus.ServiceBus, logger *logger.Logger, bindings *binding.Bindings) (*Binding, error) {
|
||||||
|
|
||||||
// Subscribe to event messages
|
// Subscribe to event messages
|
||||||
bindingChannel, err := bus.Subscribe("binding")
|
bindingChannel, err := bus.Subscribe("binding")
|
||||||
@ -37,7 +33,6 @@ func NewBinding(bus *servicebus.ServiceBus, logger *logger.Logger, bindings *bin
|
|||||||
bindingChannel: bindingChannel,
|
bindingChannel: bindingChannel,
|
||||||
logger: logger.CustomLogger("Binding Subsystem"),
|
logger: logger.CustomLogger("Binding Subsystem"),
|
||||||
bindings: bindings,
|
bindings: bindings,
|
||||||
runtime: runtime,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
|
@ -11,7 +11,6 @@ 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/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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,9 +31,6 @@ type Call struct {
|
|||||||
// logger
|
// logger
|
||||||
logger logger.CustomLogger
|
logger logger.CustomLogger
|
||||||
|
|
||||||
// runtime
|
|
||||||
runtime *runtime.Runtime
|
|
||||||
|
|
||||||
// context
|
// context
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
|
||||||
@ -43,7 +39,7 @@ type Call struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewCall creates a new call subsystem
|
// NewCall creates a new call subsystem
|
||||||
func NewCall(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger, DB *binding.DB, runtime *runtime.Runtime) (*Call, error) {
|
func NewCall(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger, DB *binding.DB) (*Call, error) {
|
||||||
|
|
||||||
// Subscribe to event messages
|
// Subscribe to event messages
|
||||||
callChannel, err := bus.Subscribe("call:invoke")
|
callChannel, err := bus.Subscribe("call:invoke")
|
||||||
@ -56,7 +52,6 @@ func NewCall(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Log
|
|||||||
logger: logger.CustomLogger("Call Subsystem"),
|
logger: logger.CustomLogger("Call Subsystem"),
|
||||||
DB: DB,
|
DB: DB,
|
||||||
bus: bus,
|
bus: bus,
|
||||||
runtime: runtime,
|
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
wg: ctx.Value("waitgroup").(*sync.WaitGroup),
|
wg: ctx.Value("waitgroup").(*sync.WaitGroup),
|
||||||
}
|
}
|
||||||
@ -130,12 +125,9 @@ func (c *Call) processSystemCall(payload *message.CallMessage, clientID string)
|
|||||||
c.logger.Trace("Got internal System call: %+v", payload)
|
c.logger.Trace("Got internal System call: %+v", payload)
|
||||||
callName := strings.TrimPrefix(payload.Name, ".wails.")
|
callName := strings.TrimPrefix(payload.Name, ".wails.")
|
||||||
switch callName {
|
switch callName {
|
||||||
case "IsDarkMode":
|
|
||||||
darkModeEnabled := c.runtime.System.IsDarkMode()
|
|
||||||
c.sendResult(darkModeEnabled, payload, clientID)
|
|
||||||
case "Dialog.Open":
|
case "Dialog.Open":
|
||||||
var dialogOptions dialog.OpenDialogOptions
|
var dialogOptions dialog.OpenDialogOptions
|
||||||
err := json.Unmarshal(payload.Args[0], dialogOptions)
|
err := json.Unmarshal(payload.Args[0], &dialogOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error("Error decoding: %s", err)
|
c.logger.Error("Error decoding: %s", err)
|
||||||
}
|
}
|
||||||
@ -146,7 +138,7 @@ func (c *Call) processSystemCall(payload *message.CallMessage, clientID string)
|
|||||||
c.sendResult(result, payload, clientID)
|
c.sendResult(result, payload, clientID)
|
||||||
case "Dialog.Save":
|
case "Dialog.Save":
|
||||||
var dialogOptions dialog.SaveDialogOptions
|
var dialogOptions dialog.SaveDialogOptions
|
||||||
err := json.Unmarshal(payload.Args[0], dialogOptions)
|
err := json.Unmarshal(payload.Args[0], &dialogOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error("Error decoding: %s", err)
|
c.logger.Error("Error decoding: %s", err)
|
||||||
}
|
}
|
||||||
@ -157,7 +149,7 @@ func (c *Call) processSystemCall(payload *message.CallMessage, clientID string)
|
|||||||
c.sendResult(result, payload, clientID)
|
c.sendResult(result, payload, clientID)
|
||||||
case "Dialog.Message":
|
case "Dialog.Message":
|
||||||
var dialogOptions dialog.MessageDialogOptions
|
var dialogOptions dialog.MessageDialogOptions
|
||||||
err := json.Unmarshal(payload.Args[0], dialogOptions)
|
err := json.Unmarshal(payload.Args[0], &dialogOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error("Error decoding: %s", err)
|
c.logger.Error("Error decoding: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,9 +21,6 @@ type Log struct {
|
|||||||
// Logger!
|
// Logger!
|
||||||
logger *logger.Logger
|
logger *logger.Logger
|
||||||
|
|
||||||
// Loglevel store
|
|
||||||
logLevelStore *runtime.Store
|
|
||||||
|
|
||||||
// Context for shutdown
|
// Context for shutdown
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
@ -34,7 +30,7 @@ type Log struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewLog creates a new log subsystem
|
// NewLog creates a new log subsystem
|
||||||
func NewLog(bus *servicebus.ServiceBus, logger *logger.Logger, logLevelStore *runtime.Store) (*Log, error) {
|
func NewLog(bus *servicebus.ServiceBus, logger *logger.Logger) (*Log, error) {
|
||||||
|
|
||||||
// Subscribe to log messages
|
// Subscribe to log messages
|
||||||
logChannel, err := bus.Subscribe("log")
|
logChannel, err := bus.Subscribe("log")
|
||||||
@ -47,7 +43,6 @@ func NewLog(bus *servicebus.ServiceBus, logger *logger.Logger, logLevelStore *ru
|
|||||||
result := &Log{
|
result := &Log{
|
||||||
logChannel: logChannel,
|
logChannel: logChannel,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
logLevelStore: logLevelStore,
|
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
}
|
}
|
||||||
@ -90,7 +85,6 @@ func (l *Log) Start() error {
|
|||||||
switch inLevel := logMessage.Data().(type) {
|
switch inLevel := logMessage.Data().(type) {
|
||||||
case logger.LogLevel:
|
case logger.LogLevel:
|
||||||
l.logger.SetLogLevel(inLevel)
|
l.logger.SetLogLevel(inLevel)
|
||||||
l.logLevelStore.Set(inLevel)
|
|
||||||
case string:
|
case string:
|
||||||
uint64level, err := strconv.ParseUint(inLevel, 10, 8)
|
uint64level, err := strconv.ParseUint(inLevel, 10, 8)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -98,7 +92,6 @@ func (l *Log) Start() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
level := logger.LogLevel(uint64level)
|
level := logger.LogLevel(uint64level)
|
||||||
l.logLevelStore.Set(level)
|
|
||||||
l.logger.SetLogLevel(level)
|
l.logger.SetLogLevel(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"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"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -25,9 +24,6 @@ type Runtime struct {
|
|||||||
|
|
||||||
logger logger.CustomLogger
|
logger logger.CustomLogger
|
||||||
|
|
||||||
// Runtime library
|
|
||||||
runtime *runtime.Runtime
|
|
||||||
|
|
||||||
//ctx
|
//ctx
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
|
||||||
@ -57,7 +53,6 @@ func NewRuntime(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.
|
|||||||
runtimeChannel: runtimeChannel,
|
runtimeChannel: runtimeChannel,
|
||||||
hooksChannel: hooksChannel,
|
hooksChannel: hooksChannel,
|
||||||
logger: logger.CustomLogger("Runtime Subsystem"),
|
logger: logger.CustomLogger("Runtime Subsystem"),
|
||||||
runtime: runtime.New(bus),
|
|
||||||
startupCallback: startupCallback,
|
startupCallback: startupCallback,
|
||||||
bus: bus,
|
bus: bus,
|
||||||
}
|
}
|
||||||
@ -98,30 +93,6 @@ func (r *Runtime) Start() error {
|
|||||||
r.logger.Error("unknown hook message: %+v", hooksMessage)
|
r.logger.Error("unknown hook message: %+v", hooksMessage)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case runtimeMessage := <-r.runtimeChannel:
|
|
||||||
r.logger.Trace(fmt.Sprintf("Received message: %+v", runtimeMessage))
|
|
||||||
// Topics have the format: "runtime:category:call"
|
|
||||||
messageSlice := strings.Split(runtimeMessage.Topic(), ":")
|
|
||||||
if len(messageSlice) != 3 {
|
|
||||||
r.logger.Error("Invalid runtime message: %#v\n", runtimeMessage)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
category := messageSlice[1]
|
|
||||||
method := messageSlice[2]
|
|
||||||
var err error
|
|
||||||
switch category {
|
|
||||||
case "browser":
|
|
||||||
err = r.processBrowserMessage(method, runtimeMessage.Data())
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("unknown runtime message: %+v",
|
|
||||||
runtimeMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we had an error, log it
|
|
||||||
if err != nil {
|
|
||||||
r.logger.Error(err.Error())
|
|
||||||
}
|
|
||||||
case <-r.ctx.Done():
|
case <-r.ctx.Done():
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -130,27 +101,3 @@ func (r *Runtime) Start() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GoRuntime returns the Go Runtime object
|
|
||||||
func (r *Runtime) GoRuntime() *runtime.Runtime {
|
|
||||||
return r.runtime
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Runtime) processBrowserMessage(method string, data interface{}) error {
|
|
||||||
switch method {
|
|
||||||
case "open":
|
|
||||||
target, ok := data.(string)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("expected 1 string parameter for runtime:browser:open")
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
err := r.runtime.Browser.Open(target)
|
|
||||||
if err != nil {
|
|
||||||
r.logger.Error(err.Error())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown method runtime:browser:%s", method)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
43
v2/pkg/runtime/Events/events.go
Normal file
43
v2/pkg/runtime/Events/events.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package events
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// On registers a listener for a particular event
|
||||||
|
func On(ctx context.Context, eventName string, callback func(optionalData ...interface{})) {
|
||||||
|
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
|
||||||
|
eventMessage := &message.OnEventMessage{
|
||||||
|
Name: eventName,
|
||||||
|
Callback: callback,
|
||||||
|
Counter: -1,
|
||||||
|
}
|
||||||
|
bus.Publish("event:on", eventMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once registers a listener for a particular event. After the first callback, the
|
||||||
|
// listener is deleted.
|
||||||
|
func Once(ctx context.Context, eventName string, callback func(optionalData ...interface{})) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
eventMessage := &message.OnEventMessage{
|
||||||
|
Name: eventName,
|
||||||
|
Callback: callback,
|
||||||
|
Counter: 1,
|
||||||
|
}
|
||||||
|
bus.Publish("event:on", eventMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit pass through
|
||||||
|
func Emit(ctx context.Context, eventName string, optionalData ...interface{}) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
eventMessage := &message.EventMessage{
|
||||||
|
Name: eventName,
|
||||||
|
Data: optionalData,
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.Publish("event:emit:from:g", eventMessage)
|
||||||
|
}
|
@ -3,9 +3,9 @@ package dialog
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/crypto"
|
"github.com/wailsapp/wails/v2/internal/crypto"
|
||||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileFilter defines a filter for dialog boxes
|
// FileFilter defines a filter for dialog boxes
|
||||||
@ -59,14 +59,6 @@ type MessageDialogOptions struct {
|
|||||||
Icon string
|
Icon string
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractBus(ctx context.Context) (*servicebus.ServiceBus, error) {
|
|
||||||
bus := ctx.Value("bus")
|
|
||||||
if bus == nil {
|
|
||||||
return nil, errors.New("wails runtime has not been initialised correctly")
|
|
||||||
}
|
|
||||||
return bus.(*servicebus.ServiceBus), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// processTitleAndFilter return the title and filter from the given params.
|
// processTitleAndFilter return the title and filter from the given params.
|
||||||
// title is the first string, filter is the second
|
// title is the first string, filter is the second
|
||||||
func processTitleAndFilter(params ...string) (string, string) {
|
func processTitleAndFilter(params ...string) (string, string) {
|
||||||
@ -84,13 +76,14 @@ func processTitleAndFilter(params ...string) (string, string) {
|
|||||||
return title, filter
|
return title, filter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fatal(caller string) {
|
||||||
|
log.Fatalf("cannot call '%s': Application not initialised", caller)
|
||||||
|
}
|
||||||
|
|
||||||
// OpenDirectory prompts the user to select a directory
|
// OpenDirectory prompts the user to select a directory
|
||||||
func OpenDirectory(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) {
|
func OpenDirectory(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) {
|
||||||
|
|
||||||
bus, err := extractBus(ctx)
|
bus := servicebus.ExtractBus(ctx)
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "OpenDirectory")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create unique dialog callback
|
// Create unique dialog callback
|
||||||
uniqueCallback := crypto.RandomID()
|
uniqueCallback := crypto.RandomID()
|
||||||
@ -117,10 +110,7 @@ func OpenDirectory(ctx context.Context, dialogOptions OpenDialogOptions) (string
|
|||||||
// OpenFile prompts the user to select a file
|
// OpenFile prompts the user to select a file
|
||||||
func OpenFile(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) {
|
func OpenFile(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) {
|
||||||
|
|
||||||
bus, err := extractBus(ctx)
|
bus := servicebus.ExtractBus(ctx)
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "OpenFile")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create unique dialog callback
|
// Create unique dialog callback
|
||||||
uniqueCallback := crypto.RandomID()
|
uniqueCallback := crypto.RandomID()
|
||||||
@ -147,12 +137,7 @@ func OpenFile(ctx context.Context, dialogOptions OpenDialogOptions) (string, err
|
|||||||
// OpenMultipleFiles prompts the user to select a file
|
// OpenMultipleFiles prompts the user to select a file
|
||||||
func OpenMultipleFiles(ctx context.Context, dialogOptions OpenDialogOptions) ([]string, error) {
|
func OpenMultipleFiles(ctx context.Context, dialogOptions OpenDialogOptions) ([]string, error) {
|
||||||
|
|
||||||
bus, err := extractBus(ctx)
|
bus := servicebus.ExtractBus(ctx)
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "OpenMultipleFiles")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create unique dialog callback
|
|
||||||
uniqueCallback := crypto.RandomID()
|
uniqueCallback := crypto.RandomID()
|
||||||
|
|
||||||
// Subscribe to the respose channel
|
// Subscribe to the respose channel
|
||||||
@ -177,12 +162,7 @@ func OpenMultipleFiles(ctx context.Context, dialogOptions OpenDialogOptions) ([]
|
|||||||
// SaveFile prompts the user to select a file
|
// SaveFile prompts the user to select a file
|
||||||
func SaveFile(ctx context.Context, dialogOptions SaveDialogOptions) (string, error) {
|
func SaveFile(ctx context.Context, dialogOptions SaveDialogOptions) (string, error) {
|
||||||
|
|
||||||
bus, err := extractBus(ctx)
|
bus := servicebus.ExtractBus(ctx)
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "SaveFile")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create unique dialog callback
|
|
||||||
uniqueCallback := crypto.RandomID()
|
uniqueCallback := crypto.RandomID()
|
||||||
|
|
||||||
// Subscribe to the respose channel
|
// Subscribe to the respose channel
|
||||||
@ -207,10 +187,7 @@ func SaveFile(ctx context.Context, dialogOptions SaveDialogOptions) (string, err
|
|||||||
// Message show a message to the user
|
// Message show a message to the user
|
||||||
func Message(ctx context.Context, dialogOptions MessageDialogOptions) (string, error) {
|
func Message(ctx context.Context, dialogOptions MessageDialogOptions) (string, error) {
|
||||||
|
|
||||||
bus, err := extractBus(ctx)
|
bus := servicebus.ExtractBus(ctx)
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "Message")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create unique dialog callback
|
// Create unique dialog callback
|
||||||
uniqueCallback := crypto.RandomID()
|
uniqueCallback := crypto.RandomID()
|
||||||
|
55
v2/pkg/runtime/log/log.go
Normal file
55
v2/pkg/runtime/log/log.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Print prints a Print level message
|
||||||
|
func Print(ctx context.Context, message string) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("log:print", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trace prints a Trace level message
|
||||||
|
func Trace(ctx context.Context, message string) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("log:trace", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug prints a Debug level message
|
||||||
|
func Debug(ctx context.Context, message string) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("log:debug", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info prints a Info level message
|
||||||
|
func Info(ctx context.Context, message string) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("log:info", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning prints a Warning level message
|
||||||
|
func Warning(ctx context.Context, message string) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("log:warning", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error prints a Error level message
|
||||||
|
func Error(ctx context.Context, message string) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("log:error", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatal prints a Fatal level message
|
||||||
|
func Fatal(ctx context.Context, message string) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("log:fatal", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogLevel sets the log level
|
||||||
|
func SetLogLevel(ctx context.Context, level logger.LogLevel) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("log:setlevel", level)
|
||||||
|
}
|
32
v2/pkg/runtime/menu/menu.go
Normal file
32
v2/pkg/runtime/menu/menu.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package menu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UpdateApplicationMenu(ctx context.Context) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("menu:updateappmenu", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateContextMenu(ctx context.Context, contextMenu *menu.ContextMenu) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("menu:updatecontextmenu", contextMenu)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetTrayMenu(ctx context.Context, trayMenu *menu.TrayMenu) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("menu:settraymenu", trayMenu)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateTrayMenuLabel(ctx context.Context, trayMenu *menu.TrayMenu) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("menu:updatetraymenulabel", trayMenu)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteTrayMenu(ctx context.Context, trayMenu *menu.TrayMenu) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("menu:deletetraymenu", trayMenu)
|
||||||
|
}
|
13
v2/pkg/runtime/runtime.go
Normal file
13
v2/pkg/runtime/runtime.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Quit the application
|
||||||
|
func Quit(ctx context.Context) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
// Start shutdown of Wails
|
||||||
|
bus.Publish("quit", "runtime.Quit()")
|
||||||
|
}
|
96
v2/pkg/runtime/window/window.go
Normal file
96
v2/pkg/runtime/window/window.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package window
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetTitle sets the title of the window
|
||||||
|
func SetTitle(ctx context.Context, title string) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("window:settitle", title)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fullscreen makes the window fullscreen
|
||||||
|
func Fullscreen(ctx context.Context) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("window:fullscreen", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnFullscreen makes the window UnFullscreen
|
||||||
|
func UnFullscreen(ctx context.Context) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("window:unfullscreen", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Center the window on the current screen
|
||||||
|
func Center(ctx context.Context) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("window:center", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show shows the window if hidden
|
||||||
|
func Show(ctx context.Context) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("window:show", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide the window
|
||||||
|
func Hide(ctx context.Context) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("window:hide", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSize sets the size of the window
|
||||||
|
func SetSize(ctx context.Context, width int, height int) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
message := fmt.Sprintf("window:size:%d:%d", width, height)
|
||||||
|
bus.Publish(message, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSize sets the size of the window
|
||||||
|
func SetMinSize(ctx context.Context, width int, height int) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
message := fmt.Sprintf("window:minsize:%d:%d", width, height)
|
||||||
|
bus.Publish(message, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSize sets the size of the window
|
||||||
|
func SetMaxSize(ctx context.Context, width int, height int) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
message := fmt.Sprintf("window:maxsize:%d:%d", width, height)
|
||||||
|
bus.Publish(message, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPosition sets the position of the window
|
||||||
|
func SetPosition(ctx context.Context, x int, y int) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
message := fmt.Sprintf("window:position:%d:%d", x, y)
|
||||||
|
bus.Publish(message, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maximise the window
|
||||||
|
func Maximise(ctx context.Context) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("window:maximise", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmaximise the window
|
||||||
|
func Unmaximise(ctx context.Context) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("window:unmaximise", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minimise the window
|
||||||
|
func Minimise(ctx context.Context) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("window:minimise", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unminimise the window
|
||||||
|
func Unminimise(ctx context.Context) {
|
||||||
|
bus := servicebus.ExtractBus(ctx)
|
||||||
|
bus.Publish("window:unminimise", "")
|
||||||
|
}
|
@ -4,13 +4,9 @@ package wails
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/v2/internal/app"
|
"github.com/wailsapp/wails/v2/internal/app"
|
||||||
"github.com/wailsapp/wails/v2/internal/runtime"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Store is an alias for the Store object
|
|
||||||
type Store = runtime.Store
|
|
||||||
|
|
||||||
// Run creates an application based on the given config and executes it
|
// Run creates an application based on the given config and executes it
|
||||||
func Run(options *options.App) error {
|
func Run(options *options.App) error {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user