mirror of
https://github.com/wavetermdev/wails.git
synced 2026-08-05 13:53:43 -07:00
Initial implementation
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
HELLO!
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"log"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
//go:embed assets/*
|
||||
var assets embed.FS
|
||||
|
||||
type RandomNumberPlugin struct{}
|
||||
|
||||
func (r *RandomNumberPlugin) Name() string {
|
||||
return "Random Number Plugin"
|
||||
}
|
||||
|
||||
func (r *RandomNumberPlugin) Init(_ *application.App) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RandomNumberPlugin) Call(args []any) (any, error) {
|
||||
return rand.Intn(100), nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
app := application.New(application.Options{
|
||||
Name: "Plugin Demo",
|
||||
Description: "A demo of the plugins API",
|
||||
Mac: application.MacOptions{
|
||||
ApplicationShouldTerminateAfterLastWindowClosed: true,
|
||||
},
|
||||
Plugins: map[string]application.Plugin{
|
||||
"random": &RandomNumberPlugin{},
|
||||
},
|
||||
Assets: application.AssetOptions{
|
||||
FS: assets,
|
||||
},
|
||||
})
|
||||
|
||||
window := app.NewWebviewWindow()
|
||||
window.ToggleDevTools()
|
||||
|
||||
err := app.Run()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
@@ -59,8 +59,10 @@ function callBinding(type, options) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function Call(options) {
|
||||
return callBinding("Call", options);
|
||||
}
|
||||
|
||||
export function Plugin(options) {
|
||||
return callBinding("Plugin", options);
|
||||
}
|
||||
@@ -167,7 +167,7 @@ export function Off(eventName, ...additionalEventNames) {
|
||||
let eventsToRemove = [eventName, ...additionalEventNames];
|
||||
eventsToRemove.forEach(eventName => {
|
||||
eventListeners.delete(eventName);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,7 @@ import * as Clipboard from './clipboard';
|
||||
import * as Application from './application';
|
||||
import * as Log from './log';
|
||||
import * as Screens from './screens';
|
||||
import {Call, callErrorCallback, callCallback} from "./calls";
|
||||
import {Plugin, Call, callErrorCallback, callCallback} from "./calls";
|
||||
import {newWindow} from "./window";
|
||||
import {dispatchCustomEvent, Emit, Off, OffAll, On, Once, OnMultiple} from "./events";
|
||||
import {dialogCallback, dialogErrorCallback, Error, Info, OpenFile, Question, SaveFile, Warning,} from "./dialogs";
|
||||
@@ -45,6 +45,7 @@ export function newRuntime(id) {
|
||||
Log,
|
||||
Screens,
|
||||
Call,
|
||||
Plugin,
|
||||
WML: {
|
||||
Reload: reloadWML,
|
||||
},
|
||||
@@ -65,7 +66,7 @@ export function newRuntime(id) {
|
||||
OffAll,
|
||||
},
|
||||
Window: newWindow(id),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -57,7 +57,8 @@ func New(appOptions Options) *App {
|
||||
result.fatal(err.Error())
|
||||
}
|
||||
|
||||
srv.UseRuntimeHandler(NewMessageProcessor())
|
||||
pluginManager := NewPluginManager(appOptions.Plugins)
|
||||
srv.UseRuntimeHandler(NewMessageProcessor(pluginManager))
|
||||
result.assets = srv
|
||||
|
||||
globalApplication = result
|
||||
|
||||
@@ -15,6 +15,11 @@ type CallOptions struct {
|
||||
Args []any `json:"args"`
|
||||
}
|
||||
|
||||
type PluginCallOptions struct {
|
||||
Name string `json:"name"`
|
||||
Args []any `json:"args"`
|
||||
}
|
||||
|
||||
// Parameter defines a Go method parameter
|
||||
type Parameter struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
@@ -12,10 +12,14 @@ import (
|
||||
// TODO maybe we could use a new struct that has the targetWindow as an attribute so we could get rid of passing the targetWindow
|
||||
// as parameter through every function call.
|
||||
|
||||
type MessageProcessor struct{}
|
||||
type MessageProcessor struct {
|
||||
pluginManager *PluginManager
|
||||
}
|
||||
|
||||
func NewMessageProcessor() *MessageProcessor {
|
||||
return &MessageProcessor{}
|
||||
func NewMessageProcessor(pluginManager *PluginManager) *MessageProcessor {
|
||||
return &MessageProcessor{
|
||||
pluginManager: pluginManager,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MessageProcessor) httpError(rw http.ResponseWriter, message string, args ...any) {
|
||||
|
||||
@@ -58,6 +58,28 @@ func (m *MessageProcessor) processCallMethod(method string, rw http.ResponseWrit
|
||||
m.callCallback(window, callID, string(jsonResult), true)
|
||||
}()
|
||||
m.ok(rw)
|
||||
case "Plugin":
|
||||
var options PluginCallOptions
|
||||
err := params.ToStruct(&options)
|
||||
if err != nil {
|
||||
m.callErrorCallback(window, "Error parsing plugin options: %s", callID, err)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
result, err := m.pluginManager.Call(options.Name, options.Args)
|
||||
if err != nil {
|
||||
m.callErrorCallback(window, "Error calling plugin: %s", callID, err)
|
||||
return
|
||||
}
|
||||
// convert result to json
|
||||
jsonResult, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
m.callErrorCallback(window, "Error converting result to json: %s", callID, err)
|
||||
return
|
||||
}
|
||||
m.callCallback(window, callID, string(jsonResult), true)
|
||||
}()
|
||||
m.ok(rw)
|
||||
default:
|
||||
m.httpError(rw, "Unknown dialog method: %s", method)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ type Options struct {
|
||||
Silent bool
|
||||
CustomLoggers []logger.Output
|
||||
}
|
||||
Assets AssetOptions
|
||||
Assets AssetOptions
|
||||
Plugins map[string]Plugin
|
||||
}
|
||||
|
||||
// AssetOptions defines the configuration of the AssetServer.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Plugin interface {
|
||||
Name() string
|
||||
Init(app *App) error
|
||||
Call(args []any) (any, error)
|
||||
}
|
||||
|
||||
type PluginManager struct {
|
||||
plugins map[string]Plugin
|
||||
}
|
||||
|
||||
func NewPluginManager(plugins map[string]Plugin) *PluginManager {
|
||||
return &PluginManager{
|
||||
plugins: plugins,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PluginManager) Init() error {
|
||||
for _, plugin := range p.plugins {
|
||||
err := plugin.Init(globalApplication)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
globalApplication.info("Plugin '%s' initialised", plugin.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PluginManager) Call(name string, args []any) (any, error) {
|
||||
plugin, ok := p.plugins[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin '%s' not found", name)
|
||||
}
|
||||
return plugin.Call(args)
|
||||
}
|
||||
Reference in New Issue
Block a user