mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-14 14:45:49 +01:00
[V3] Plugins implemenations (#3570)
* plugin handler and lifecycle * rebase * remove reflect s * remove Config and NewPlugin from plugin template * Remove plugin manager, generation of plugin interface * implement http handlers for services remove log trim path prefix wails/services * update plugine example * Misc updates * Ported plugins to services, rewritten example * Added fileserver * Update OnStartup and use a context for the application * Rename PathPrefix to Route. Create docs. * Use service config copy. Add Name to Service Options. Improve service generation. * Use service config copy. Add Name to Service Options. Improve service generation. Update README * Remove rogue db * Update changelog.md --------- Co-authored-by: Lea O'Anthony <lea.anthony@gmail.com>
This commit is contained in:
parent
60c9d1a070
commit
e316cd0719
78 changed files with 1362 additions and 1813 deletions
|
|
@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Added
|
||||
- [windows] Window class name option by [windom](https://github.com/windom/) in [#3682](https://github.com/wailsapp/wails/pull/3682)
|
||||
- Services have been expanded to provide plugin functionality. By [atterpac](https://github.com/atterpac) and [leaanthony](https://github.com/leaanthony) in [#3570](https://github.com/wailsapp/wails/pull/3570)
|
||||
|
||||
### Fixed
|
||||
- [windows] Fixed syso icon file generation bug by [atterpac](https://github.com/atterpac) in [#3675](https://github.com/wailsapp/wails/pull/3675)
|
||||
|
|
|
|||
145
mkdocs-website/docs/en/learn/services.md
Normal file
145
mkdocs-website/docs/en/learn/services.md
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
# Services
|
||||
|
||||
Services in Wails v3 provide a powerful way to extend the functionality of your application. They allow you to create
|
||||
modular, reusable components that can be easily integrated into your Wails application.
|
||||
|
||||
## Overview
|
||||
|
||||
Services are designed to encapsulate specific functionality and can be registered with the application at startup.
|
||||
They can handle various tasks such as file serving, database operations, logging, and more.
|
||||
Services can also interact with the application lifecycle and respond to HTTP requests.
|
||||
|
||||
## Creating a Service
|
||||
|
||||
To create a service, you simply define a struct. Here's a basic structure of a service:
|
||||
|
||||
```go
|
||||
type MyService struct {
|
||||
// Your service fields
|
||||
}
|
||||
|
||||
func NewMyService() *MyService {
|
||||
// Initialize and return your service
|
||||
}
|
||||
|
||||
func (s *MyService) Greet(name string) string {
|
||||
return fmt.Sprintf("Hello, %s!", name)
|
||||
}
|
||||
```
|
||||
|
||||
This service has a single method, `Greet`, which accepts a name and returns a greeting.
|
||||
|
||||
## Registering a Service
|
||||
|
||||
To register a service with the application, you need to provide an instance of the service to the `Services` field of
|
||||
the `application.Options` struct (All services need to be wrapped by an `application.NewService` call. Here's an example:
|
||||
|
||||
```go
|
||||
app := application.New(application.Options{
|
||||
Services: []application.Service{
|
||||
application.NewService(NewMyService()),
|
||||
},
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
## Optional Methods
|
||||
|
||||
Services can implement optional methods to hook into the application lifecycle:
|
||||
|
||||
### Name
|
||||
|
||||
```go
|
||||
func (s *Service) Name() string
|
||||
```
|
||||
|
||||
This method returns the name of the service. It is used for logging purposes only.
|
||||
|
||||
### OnStartup
|
||||
|
||||
```go
|
||||
func (s *Service) OnStartup(ctx context.Context, options application.ServiceOptions) error
|
||||
```
|
||||
|
||||
This method is called when the application is starting up. You can use it to initialize resources, set up connections,
|
||||
or perform any necessary setup tasks. The context is the application context, and the `options` parameter provides
|
||||
additional information about the service.
|
||||
|
||||
### OnShutdown
|
||||
|
||||
```go
|
||||
func (s *Service) OnShutdown() error
|
||||
```
|
||||
|
||||
This method is called when the application is shutting down. Use it to clean up resources, close connections, or
|
||||
perform any necessary cleanup tasks.
|
||||
|
||||
### ServeHTTP
|
||||
|
||||
```go
|
||||
func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request)
|
||||
```
|
||||
|
||||
If your service needs to handle HTTP requests, implement this method. It allows your service to act as an HTTP handler.
|
||||
The route of the handler is defined in the service options:
|
||||
|
||||
```go
|
||||
application.NewService(fileserver.New(&fileserver.Config{
|
||||
RootPath: rootPath,
|
||||
}), application.ServiceOptions{
|
||||
Route: "/files",
|
||||
}),
|
||||
```
|
||||
|
||||
## Example: File Server Service
|
||||
|
||||
Let's look at a simplified version of the `fileserver` service as an example:
|
||||
|
||||
```go
|
||||
type Service struct {
|
||||
config *Config
|
||||
fs http.Handler
|
||||
}
|
||||
|
||||
func New(config *Config) *Service {
|
||||
return &Service{
|
||||
config: config,
|
||||
fs: http.FileServer(http.Dir(config.RootPath)),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) Name() string {
|
||||
return "github.com/wailsapp/wails/v3/services/fileserver"
|
||||
}
|
||||
|
||||
func (s *Service) OnStartup(ctx context.Context, options application.ServiceOptions) error {
|
||||
// Any initialization code here
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
s.fs.ServeHTTP(w, r)
|
||||
}
|
||||
```
|
||||
|
||||
We can now use this service in our application:
|
||||
|
||||
```go
|
||||
app := application.New(application.Options{
|
||||
Services: []application.Service{
|
||||
application.NewService(fileserver.New(&fileserver.Config{
|
||||
RootPath: rootPath,
|
||||
}), application.ServiceOptions{
|
||||
Route: "/files",
|
||||
}),
|
||||
```
|
||||
All requests to `/files` will be handled by the `fileserver` service.
|
||||
|
||||
## Application Lifecycle and Services
|
||||
|
||||
1. During application initialization, services are registered with the application.
|
||||
2. When the application starts (`app.Run()`), the `OnStartup` method of each service is called with the application
|
||||
context and service options.
|
||||
3. Throughout the application's lifetime, services can perform their specific tasks.
|
||||
4. If a service implements `ServeHTTP`, it can handle HTTP requests at the specified path.
|
||||
5. When the application is shutting down, the `OnShutdown` method of each service is called as well as the context being cancelled.
|
||||
|
|
@ -143,6 +143,7 @@ nav:
|
|||
- Your First Application: getting-started/your-first-app.md
|
||||
- Next Steps: getting-started/next-steps.md
|
||||
- Learn More:
|
||||
- Services: learn/services.md
|
||||
- Runtime: learn/runtime.md
|
||||
- Plugins: learn/plugins.md
|
||||
- Guides:
|
||||
|
|
|
|||
|
|
@ -57,10 +57,8 @@ func main() {
|
|||
generate.NewSubCommandFunction(".desktop", "Generate .desktop file", commands.GenerateDotDesktop)
|
||||
generate.NewSubCommandFunction("appimage", "Generate Linux AppImage", commands.GenerateAppImage)
|
||||
|
||||
plugin := app.NewSubCommand("plugin", "Plugin tools")
|
||||
//plugin.NewSubCommandFunction("list", "List plugins", commands.PluginList)
|
||||
plugin.NewSubCommandFunction("init", "Initialise a new plugin", commands.PluginInit)
|
||||
//plugin.NewSubCommandFunction("add", "Add a plugin", commands.PluginAdd)
|
||||
plugin := app.NewSubCommand("service", "Service tools")
|
||||
plugin.NewSubCommandFunction("init", "Initialise a new service", commands.ServiceInit)
|
||||
tool := app.NewSubCommand("tool", "Various tools")
|
||||
tool.NewSubCommandFunction("checkport", "Checks if a port is open. Useful for testing if vite is running.", commands.ToolCheckPort)
|
||||
tool.NewSubCommandFunction("watcher", "Watches files and runs a command when they change", commands.Watcher)
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
# Plugins Example
|
||||
|
||||
This example is not ready for testing yet.
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
version: '3'
|
||||
|
||||
tasks:
|
||||
|
||||
pre-build:
|
||||
summary: Pre-build hooks
|
||||
|
||||
post-build:
|
||||
summary: Post-build hooks
|
||||
|
||||
build:
|
||||
summary: Builds the application
|
||||
cmds:
|
||||
- task: pre-build
|
||||
- go build -gcflags=all="-N -l" -o bin/testapp main.go
|
||||
- task: post-build
|
||||
env:
|
||||
CGO_CFLAGS: "-mmacosx-version-min=10.13"
|
||||
CGO_LDFLAGS: "-mmacosx-version-min=10.13"
|
||||
MACOSX_DEPLOYMENT_TARGET: "10.13"
|
||||
|
||||
generate-icons:
|
||||
summary: Generates Windows `.ico` and Mac `.icns` files from an image
|
||||
cmds:
|
||||
# Generates both .ico and .icns files
|
||||
- wails generate icons -input build/appicon.png
|
||||
|
||||
build-prod:
|
||||
summary: Creates a production build of the application
|
||||
cmds:
|
||||
- go build -tags production -ldflags="-w -s" -o bin/testapp
|
||||
|
||||
package-darwin:
|
||||
summary: Packages a production build of the application into a `.app` bundle
|
||||
deps:
|
||||
- build-prod
|
||||
- generate-icons
|
||||
cmds:
|
||||
- mkdir -p buildtest.app/Contents/{MacOS,Resources}
|
||||
- cp build/icons.icns buildtest.app/Contents/Resources
|
||||
- cp bin/testapp buildtest.app/Contents/MacOS
|
||||
- cp build/Info.plist buildtest.app/Contents
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>My App</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>app</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.wails.app</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>v1.0.0</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>The ultimate thing</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>v1</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>icons</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.13.0</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<string>true</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>(c) Me</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>My App</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>testapp</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.wails.app</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>v1.0.0</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>The ultimate thing</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>v1</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>icons</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.13.0</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<string>true</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>(c) Me</string>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 130 KiB |
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"fixed": {
|
||||
"file_version": "v1.0.0"
|
||||
},
|
||||
"info": {
|
||||
"0000": {
|
||||
"ProductVersion": "v1.0.0",
|
||||
"CompanyName": "My Company Name",
|
||||
"FileDescription": "A thing that does a thing",
|
||||
"LegalCopyright": "(c) 2023 My Company Name",
|
||||
"ProductName": "My Product Name",
|
||||
"Comments": "This is a comment"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<assemblyIdentity type="win32" name="com.wails.myproductname" version="v1.0.0.0" processorArchitecture="*"/>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware> <!-- fallback for Windows 7 and 8 -->
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness> <!-- falls back to per-monitor if per-monitor v2 is not supported -->
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
</assembly>
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
module plugin_demo
|
||||
|
||||
go 1.22
|
||||
|
||||
toolchain go1.22.0
|
||||
|
||||
require github.com/wailsapp/wails/v3 v3.0.0-alpha.0
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
|
||||
github.com/bep/debounce v1.2.1 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/ebitengine/purego v0.4.0-alpha.4 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.5.0 // indirect
|
||||
github.com/go-git/go-git/v5 v5.11.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
|
||||
github.com/leaanthony/u v1.1.0 // indirect
|
||||
github.com/lmittmann/tint v1.0.3 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/samber/lo v1.38.1 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/skeema/knownhosts v1.2.1 // indirect
|
||||
github.com/wailsapp/go-webview2 v1.0.9 // indirect
|
||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
golang.org/x/crypto v0.21.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/net v0.21.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/tools v0.13.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
lukechampine.com/uint128 v1.2.0 // indirect
|
||||
modernc.org/cc/v3 v3.40.0 // indirect
|
||||
modernc.org/ccgo/v3 v3.16.13 // indirect
|
||||
modernc.org/libc v1.22.3 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/opt v0.1.3 // indirect
|
||||
modernc.org/sqlite v1.21.0 // indirect
|
||||
modernc.org/strutil v1.1.3 // indirect
|
||||
modernc.org/token v1.0.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/wailsapp/wails/v3 => ../..
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/ebitengine/purego v0.4.0-alpha.4 h1:Y7yIV06Yo5M2BAdD7EVPhfp6LZ0tEcQo5770OhYUVes=
|
||||
github.com/ebitengine/purego v0.4.0-alpha.4/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
|
||||
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A=
|
||||
github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
|
||||
github.com/leaanthony/u v1.1.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI=
|
||||
github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
|
||||
github.com/lmittmann/tint v1.0.3 h1:W5PHeA2D8bBJVvabNfQD/XW9HPLZK1XoPZH0cq8NouQ=
|
||||
github.com/lmittmann/tint v1.0.3/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
|
||||
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/wailsapp/go-webview2 v1.0.9 h1:lrU+q0cf1wgLdR69rN+ZnRtMJNaJRrcQ4ELxoO7/xjs=
|
||||
github.com/wailsapp/go-webview2 v1.0.9/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
|
||||
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
|
||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
|
||||
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
|
||||
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
|
||||
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
|
||||
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
|
||||
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
|
||||
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
||||
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||
modernc.org/libc v1.22.3 h1:D/g6O5ftAfavceqlLOFwaZuA5KYafKwmr30A6iSqoyY=
|
||||
modernc.org/libc v1.22.3/go.mod h1:MQrloYP209xa2zHome2a8HLiLm6k0UT8CoHpV74tOFw=
|
||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
|
||||
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sqlite v1.21.0 h1:4aP4MdUf15i3R3M2mx6Q90WHKz3nZLoz96zlB6tNdow=
|
||||
modernc.org/sqlite v1.21.0/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI=
|
||||
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
|
||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
||||
modernc.org/tcl v1.15.1 h1:mOQwiEK4p7HruMZcwKTZPw/aqtGM4aY00uzWhlKKYws=
|
||||
modernc.org/tcl v1.15.1/go.mod h1:aEjeGJX2gz1oWKOLDVZ2tnEWLUrIn8H+GFu+akoDhqs=
|
||||
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
|
||||
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE=
|
||||
modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ=
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
# Hashes Plugin
|
||||
|
||||
This example plugin provides a way to generate hashes of strings.
|
||||
|
||||
## Usage
|
||||
|
||||
Add the plugin to the `Plugins` option in the Applications options:
|
||||
|
||||
```go
|
||||
Plugins: map[string]application.Plugin{
|
||||
"hashes": hashes.NewPlugin(),
|
||||
},
|
||||
```
|
||||
|
||||
You can then call the Generate method from the frontend:
|
||||
|
||||
```js
|
||||
import {Call} from "/wails/runtime.js";
|
||||
Call.Plugin("hashes","Generate","hello world").then((result) => console.log(result))
|
||||
```
|
||||
|
||||
This method returns a struct with the following fields:
|
||||
|
||||
```typescript
|
||||
interface Hashes {
|
||||
md5: string;
|
||||
sha1: string;
|
||||
sha256: string;
|
||||
}
|
||||
```
|
||||
|
||||
A TypeScript definition file is provided for this interface.
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
package hashes
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
// ---------------- Plugin Setup ----------------
|
||||
|
||||
type Plugin struct{}
|
||||
|
||||
func NewPlugin() *Plugin {
|
||||
return &Plugin{}
|
||||
}
|
||||
|
||||
func (r *Plugin) Shutdown() error { return nil }
|
||||
|
||||
func (r *Plugin) Name() string {
|
||||
return "Hashes Plugin"
|
||||
}
|
||||
|
||||
func (r *Plugin) Init(api application.PluginAPI) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Plugin) CallableByJS() []string {
|
||||
return []string{
|
||||
"Generate",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Plugin) Assets() fs.FS {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ---------------- Plugin Methods ----------------
|
||||
|
||||
type Hashes struct {
|
||||
MD5 string `json:"md5"`
|
||||
SHA1 string `json:"sha1"`
|
||||
SHA256 string `json:"sha256"`
|
||||
}
|
||||
|
||||
func (r *Plugin) Generate(s string) Hashes {
|
||||
md5Hash := md5.Sum([]byte(s))
|
||||
sha1Hash := sha1.Sum([]byte(s))
|
||||
sha256Hash := sha256.Sum256([]byte(s))
|
||||
|
||||
return Hashes{
|
||||
MD5: hex.EncodeToString(md5Hash[:]),
|
||||
SHA1: hex.EncodeToString(sha1Hash[:]),
|
||||
SHA256: hex.EncodeToString(sha256Hash[:]),
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
# This is the plugin definition file for the "Hashes" plugin.
|
||||
|
||||
Name = "Hashes"
|
||||
Description = "Provides a method to generate a number of hashes."
|
||||
Author = "Lea Anthony"
|
||||
Version = "v1.0.0"
|
||||
Website = "https://wails.io"
|
||||
License = "MIT"
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB |
Binary file not shown.
|
|
@ -1,61 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"log/slog"
|
||||
"os"
|
||||
"plugin_demo/hashes"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"github.com/wailsapp/wails/v3/plugins/kvstore"
|
||||
"github.com/wailsapp/wails/v3/plugins/log"
|
||||
"github.com/wailsapp/wails/v3/plugins/single_instance"
|
||||
"github.com/wailsapp/wails/v3/plugins/sqlite"
|
||||
"github.com/wailsapp/wails/v3/plugins/start_at_login"
|
||||
)
|
||||
|
||||
//go:embed assets/*
|
||||
var assets embed.FS
|
||||
|
||||
func main() {
|
||||
|
||||
app := application.New(application.Options{
|
||||
Name: "Plugin Demo",
|
||||
Description: "A demo of the plugins API",
|
||||
Mac: application.MacOptions{
|
||||
ApplicationShouldTerminateAfterLastWindowClosed: true,
|
||||
},
|
||||
LogLevel: slog.LevelDebug,
|
||||
Plugins: map[string]application.Plugin{
|
||||
"hashes": hashes.NewPlugin(),
|
||||
"log": log.NewPlugin(),
|
||||
"sqlite": sqlite.NewPlugin(&sqlite.Config{
|
||||
DBFile: "test.db",
|
||||
}),
|
||||
"kvstore": kvstore.NewPlugin(&kvstore.Config{
|
||||
Filename: "store.json",
|
||||
AutoSave: true,
|
||||
}),
|
||||
"single_instance": single_instance.NewPlugin(&single_instance.Config{
|
||||
// When true, the original app will be activated when a second instance is launched
|
||||
ActivateAppOnSubsequentLaunch: true,
|
||||
}),
|
||||
"start_at_login": start_at_login.NewPlugin(start_at_login.Config{}),
|
||||
},
|
||||
Assets: application.AssetOptions{
|
||||
Handler: application.BundledAssetFileServer(assets),
|
||||
},
|
||||
})
|
||||
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Width: 1024,
|
||||
Height: 768,
|
||||
})
|
||||
|
||||
err := app.Run()
|
||||
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Call as $Call, Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as $models from "./models.js";
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
* @returns {Promise<$models.Hashes> & { cancel(): void }}
|
||||
*/
|
||||
export function Generate(s) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(1640814231, s));
|
||||
let $typingPromise = /** @type {any} */($resultPromise.then(($result) => {
|
||||
return $$createType0($result);
|
||||
}));
|
||||
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||
return $typingPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<string> & { cancel(): void }}
|
||||
*/
|
||||
export function Name() {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(2815914379));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
// Private type creation functions
|
||||
const $$createType0 = $models.Hashes.createFrom;
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
import * as Hashes from "./hashes.js";
|
||||
export {
|
||||
Hashes
|
||||
};
|
||||
|
||||
export * from "./models.js";
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
export class Hashes {
|
||||
/**
|
||||
* Creates a new Hashes instance.
|
||||
* @param {Partial<Hashes>} [$$source = {}] - The source object to create the Hashes.
|
||||
*/
|
||||
constructor($$source = {}) {
|
||||
if (!("md5" in $$source)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["md5"] = "";
|
||||
}
|
||||
if (!("sha1" in $$source)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["sha1"] = "";
|
||||
}
|
||||
if (!("sha256" in $$source)) {
|
||||
/**
|
||||
* @member
|
||||
* @type {string}
|
||||
*/
|
||||
this["sha256"] = "";
|
||||
}
|
||||
|
||||
Object.assign(this, $$source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Hashes instance from a string or object.
|
||||
* @param {any} [$$source = {}]
|
||||
* @returns {Hashes}
|
||||
*/
|
||||
static createFrom($$source = {}) {
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
return new Hashes(/** @type {Partial<Hashes>} */($$parsedSource));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
import * as KeyValueStore from "./keyvaluestore.js";
|
||||
export {
|
||||
KeyValueStore
|
||||
};
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Call as $Call, Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
/**
|
||||
* Delete deletes the key from the store. If AutoSave is true, the store is saved to disk.
|
||||
* @param {string} key
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
*/
|
||||
export function Delete(key) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(1029952841, key));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get returns the value for the given key. If key is empty, the entire store is returned.
|
||||
* @param {string} key
|
||||
* @returns {Promise<any> & { cancel(): void }}
|
||||
*/
|
||||
export function Get(key) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(3017738442, key));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name returns the name of the plugin.
|
||||
* @returns {Promise<string> & { cancel(): void }}
|
||||
*/
|
||||
export function Name() {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(2879709053));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save saves the store to disk
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
*/
|
||||
export function Save() {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(840897339));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sets the value for the given key. If AutoSave is true, the store is saved to disk.
|
||||
* @param {string} key
|
||||
* @param {any} value
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
*/
|
||||
export function Set(key, value) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(2329265830, key, value));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
import * as LoggerService from "./loggerservice.js";
|
||||
export {
|
||||
LoggerService
|
||||
};
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Call as $Call, Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import * as slog$0 from "../../../../../../../log/slog/models.js";
|
||||
|
||||
/**
|
||||
* @param {string} message
|
||||
* @param {any[]} args
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
*/
|
||||
export function Debug(message, ...args) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(1384012895, message, args));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} message
|
||||
* @param {any[]} args
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
*/
|
||||
export function Error(message, ...args) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(1324251502, message, args));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} message
|
||||
* @param {any[]} args
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
*/
|
||||
export function Info(message, ...args) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(3712350036, message, args));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name returns the name of the plugin.
|
||||
* You should use the go module format e.g. github.com/myuser/myplugin
|
||||
* @returns {Promise<string> & { cancel(): void }}
|
||||
*/
|
||||
export function Name() {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(3407342027));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {slog$0.Level} level
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
*/
|
||||
export function SetLogLevel(level) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(2521579448, level));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} message
|
||||
* @param {any[]} args
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
*/
|
||||
export function Warning(message, ...args) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(2902024404, message, args));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
import * as Service from "./service.js";
|
||||
export {
|
||||
Service
|
||||
};
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Call as $Call, Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
/**
|
||||
* @returns {Promise<string> & { cancel(): void }}
|
||||
*/
|
||||
export function Close() {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(1888105376));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} query
|
||||
* @param {any[]} args
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
*/
|
||||
export function Execute(query, ...args) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(3811930203, query, args));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name returns the name of the plugin.
|
||||
* You should use the go module format e.g. github.com/myuser/myplugin
|
||||
* @returns {Promise<string> & { cancel(): void }}
|
||||
*/
|
||||
export function Name() {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(2075046103));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} dbPath
|
||||
* @returns {Promise<string> & { cancel(): void }}
|
||||
*/
|
||||
export function Open(dbPath) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(2012175612, dbPath));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} query
|
||||
* @param {any[]} args
|
||||
* @returns {Promise<{ [_: string]: any }[]> & { cancel(): void }}
|
||||
*/
|
||||
export function Select(query, ...args) {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(2472933124, query, args));
|
||||
let $typingPromise = /** @type {any} */($resultPromise.then(($result) => {
|
||||
return $$createType1($result);
|
||||
}));
|
||||
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||
return $typingPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown is called when the app is shutting down
|
||||
* You can use this to clean up any resources you have allocated
|
||||
* @returns {Promise<void> & { cancel(): void }}
|
||||
*/
|
||||
export function Shutdown() {
|
||||
let $resultPromise = /** @type {any} */($Call.ByID(846401686));
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
// Private type creation functions
|
||||
const $$createType0 = $Create.Map($Create.Any, $Create.Any);
|
||||
const $$createType1 = $Create.Array($$createType0);
|
||||
5
v3/examples/services/assets/bindings/log/slog/index.js
Normal file
5
v3/examples/services/assets/bindings/log/slog/index.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export * from "./models.js";
|
||||
13
v3/examples/services/assets/bindings/log/slog/models.js
Normal file
13
v3/examples/services/assets/bindings/log/slog/models.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: Unused imports
|
||||
import {Create as $Create} from "/wails/runtime.js";
|
||||
|
||||
/**
|
||||
* A Level is the importance or severity of a log event.
|
||||
* The higher the level, the more important or severe the event.
|
||||
* @typedef {any} Level
|
||||
*/
|
||||
|
|
@ -6,15 +6,15 @@
|
|||
<link rel="stylesheet" href="/style.css">
|
||||
<script type="module" src="/wails/runtime.js"></script>
|
||||
<script type="module">
|
||||
import * as sqlite from '/wails/plugin/sqlite/sqlite.js';
|
||||
import {Call} from "/wails/runtime.js";
|
||||
import * as kvpairs from '/wails/plugin/kvstore/kvstore.js';
|
||||
import {Debug, Info, Warning, Error} from '/wails/plugin/log/log.js';
|
||||
import * as sqlite from './bindings/github.com/wailsapp/wails/v3/pkg/services/sqlite/service.js';
|
||||
import * as kvstore from './bindings/github.com/wailsapp/wails/v3/pkg/services/kvstore/keyvaluestore.js';
|
||||
import {Debug, Info, Warning, Error} from './bindings/github.com/wailsapp/wails/v3/pkg/services/log/loggerservice.js';
|
||||
import * as hash from './bindings/github.com/wailsapp/wails/v3/examples/services/hashes/hashes.js';
|
||||
|
||||
function runHash() {
|
||||
let hashstring = document.getElementById("hashstring").value;
|
||||
// Plugin methods can be called by name using the Plugin method
|
||||
Call.Plugin("hashes", "Generate", hashstring).then((result) => {
|
||||
hash.Generate(hashstring).then((result) => {
|
||||
// Result is an object with the hash and the algorithm used is the key
|
||||
// Output a table with the field name in the left cell and the value in the right
|
||||
let table = document.createElement("table");
|
||||
|
|
@ -84,14 +84,14 @@
|
|||
}
|
||||
|
||||
function deleteKVPair(key) {
|
||||
kvpairs.Delete(key).then(() => {
|
||||
kvstore.Delete(key).then(() => {
|
||||
getKVStoreValues();
|
||||
}).catch((err) => {
|
||||
document.getElementById("kvstoreresults").innerHTML = err;
|
||||
});
|
||||
}
|
||||
function getKVStoreValues() {
|
||||
kvpairs.Get().then((result) => {
|
||||
kvstore.Get("").then((result) => {
|
||||
let kvstoreresults = document.getElementById('kvstoreresults');
|
||||
kvstoreresults.innerHTML = '';
|
||||
let table = document.createElement('table');
|
||||
|
|
@ -175,7 +175,7 @@
|
|||
// Validate the key and value
|
||||
if (key) {
|
||||
// Call the Set method
|
||||
kvpairs.Set(key, value);
|
||||
kvstore.Set(key, value);
|
||||
// Get all values from the kvstore
|
||||
getKVStoreValues();
|
||||
} else {
|
||||
|
|
@ -224,7 +224,7 @@
|
|||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Plugins</h2>
|
||||
<h2>Services</h2>
|
||||
<div>
|
||||
<div class="tab" style="--wails-draggable: drag">
|
||||
<button class="tablinks defaultOpen" onclick="openTab('sqlite')">SQLite</button>
|
||||
|
|
@ -232,14 +232,13 @@
|
|||
<button class="tablinks" onclick="openTab('kvstore')">K/V Store</button>
|
||||
<button class="tablinks" onclick="openTab('log')">Log</button>
|
||||
</div>
|
||||
|
||||
<div id="sqlite" class="tabcontent">
|
||||
<p>The sqlite plugin provides easy integration with sqlite dbs.</p>
|
||||
<p>The sqlite service provides easy integration with sqlite dbs.</p>
|
||||
<p>The demo DB has a single table: Users.</p>
|
||||
<p>Enter a query below and hit the "Run" button.</p>
|
||||
<div>
|
||||
<div style="display: flex;justify-content: space-around;">
|
||||
<input style="width:90%" type="text" id="query" value="select * from Users where age > 20"><br/>
|
||||
<input style="width:90%" type="text" id="query" value="select * from users where age > 20"><br/>
|
||||
<button type="button" id="runquery">Run</button>
|
||||
</div>
|
||||
<div id="sqlresults">
|
||||
|
|
@ -247,7 +246,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="hashes" class="tabcontent">
|
||||
<p>The hashes plugin provides hashing functions.</p>
|
||||
<p>The hashes service provides hashing functions.</p>
|
||||
<div>
|
||||
<div style="display: flex;justify-content: space-around;">
|
||||
<input style="width:90%" type="text" id="hashstring" placeholder="Type any string here..."><br/>
|
||||
|
|
@ -258,7 +257,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="kvstore" class="tabcontent">
|
||||
<p>The kvstore plugin provides a means for reading and writing to a json file.</p>
|
||||
<p>The kvstore service provides a means for reading and writing to a json file.</p>
|
||||
<p>Enter a key/value pair in the form below to add it to the file.</p>
|
||||
<p>A blank value will remove the key.</p>
|
||||
<div>
|
||||
|
|
@ -7,6 +7,8 @@ html {
|
|||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
|
|
@ -16,6 +18,15 @@ body {
|
|||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
overscroll-behavior: none;
|
||||
overflow-y: hidden;
|
||||
background-image: url("/files/images/eryri1.png");
|
||||
background-color: rgba(33, 37, 43, 0.85);
|
||||
background-blend-mode: overlay;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.logo {
|
||||
BIN
v3/examples/services/files/images/eryri1.png
Normal file
BIN
v3/examples/services/files/images/eryri1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 657 KiB |
40
v3/examples/services/hashes/hashes.go
Normal file
40
v3/examples/services/hashes/hashes.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package hashes
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
type Hashes struct {
|
||||
MD5 string `json:"md5"`
|
||||
SHA1 string `json:"sha1"`
|
||||
SHA256 string `json:"sha256"`
|
||||
}
|
||||
|
||||
func (h *Hashes) Generate(s string) Hashes {
|
||||
md5Hash := md5.Sum([]byte(s))
|
||||
sha1Hash := sha1.Sum([]byte(s))
|
||||
sha256Hash := sha256.Sum256([]byte(s))
|
||||
|
||||
return Hashes{
|
||||
MD5: hex.EncodeToString(md5Hash[:]),
|
||||
SHA1: hex.EncodeToString(sha1Hash[:]),
|
||||
SHA256: hex.EncodeToString(sha256Hash[:]),
|
||||
}
|
||||
}
|
||||
|
||||
func New() *Hashes {
|
||||
return &Hashes{}
|
||||
}
|
||||
|
||||
func (h *Hashes) OnShutdown() error { return nil }
|
||||
|
||||
func (h *Hashes) Name() string {
|
||||
return "Hashes Service"
|
||||
}
|
||||
|
||||
func (h *Hashes) OnStartup() error {
|
||||
return nil
|
||||
}
|
||||
61
v3/examples/services/main.go
Normal file
61
v3/examples/services/main.go
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"github.com/wailsapp/wails/v3/examples/services/hashes"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"github.com/wailsapp/wails/v3/pkg/services/fileserver"
|
||||
"github.com/wailsapp/wails/v3/pkg/services/kvstore"
|
||||
"github.com/wailsapp/wails/v3/pkg/services/log"
|
||||
"github.com/wailsapp/wails/v3/pkg/services/sqlite"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
//go:embed assets/*
|
||||
var assets embed.FS
|
||||
|
||||
func main() {
|
||||
|
||||
rootPath, _ := filepath.Abs("./files")
|
||||
app := application.New(application.Options{
|
||||
Name: "Services Demo",
|
||||
Description: "A demo of the services API",
|
||||
Mac: application.MacOptions{
|
||||
ApplicationShouldTerminateAfterLastWindowClosed: true,
|
||||
},
|
||||
LogLevel: slog.LevelDebug,
|
||||
Services: []application.Service{
|
||||
application.NewService(hashes.New()),
|
||||
application.NewService(sqlite.New(&sqlite.Config{
|
||||
DBFile: "test.db",
|
||||
})),
|
||||
application.NewService(kvstore.New(&kvstore.Config{
|
||||
Filename: "store.json",
|
||||
AutoSave: true,
|
||||
})),
|
||||
application.NewService(log.New()),
|
||||
application.NewService(fileserver.New(&fileserver.Config{
|
||||
RootPath: rootPath,
|
||||
}), application.ServiceOptions{
|
||||
Route: "/files",
|
||||
}),
|
||||
},
|
||||
Assets: application.AssetOptions{
|
||||
Handler: application.BundledAssetFileServer(assets),
|
||||
},
|
||||
})
|
||||
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Width: 1024,
|
||||
Height: 768,
|
||||
})
|
||||
|
||||
err := app.Run()
|
||||
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,11 @@
|
|||
package assetserver
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
|
@ -16,7 +13,7 @@ import (
|
|||
const (
|
||||
webViewRequestHeaderWindowId = "x-wails-window-id"
|
||||
webViewRequestHeaderWindowName = "x-wails-window-name"
|
||||
pluginPrefix = "/wails/plugin"
|
||||
servicePrefix = "wails/services"
|
||||
)
|
||||
|
||||
type RuntimeHandler interface {
|
||||
|
|
@ -28,16 +25,14 @@ type AssetServer struct {
|
|||
|
||||
handler http.Handler
|
||||
|
||||
//pluginScripts map[string]string
|
||||
services map[string]http.Handler
|
||||
|
||||
assetServerWebView
|
||||
pluginAssets map[string]fs.FS
|
||||
}
|
||||
|
||||
func NewAssetServer(options *Options) (*AssetServer, error) {
|
||||
result := &AssetServer{
|
||||
options: options,
|
||||
pluginAssets: make(map[string]fs.FS),
|
||||
options: options,
|
||||
}
|
||||
|
||||
userHandler := options.Handler
|
||||
|
|
@ -113,39 +108,35 @@ func (a *AssetServer) serveHTTP(rw http.ResponseWriter, req *http.Request, userH
|
|||
|
||||
default:
|
||||
|
||||
// Check if this is a plugin asset
|
||||
if !strings.HasPrefix(reqPath, pluginPrefix) {
|
||||
userHandler.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure there is 4 parts to the reqPath
|
||||
parts := strings.SplitN(reqPath, "/", 5)
|
||||
if len(parts) < 5 {
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
// Get the first 3 parts of the reqPath
|
||||
pluginPath := "/" + path.Join(parts[1], parts[2], parts[3])
|
||||
// Get the remaining part of the reqPath
|
||||
fileName := parts[4]
|
||||
|
||||
// Check if this is a registered plugin asset
|
||||
if assetFS, ok := a.pluginAssets[pluginPath]; ok {
|
||||
// Check if the file exists
|
||||
file, err := fs.ReadFile(assetFS, fileName)
|
||||
if err != nil {
|
||||
a.serveError(rw, err, "Unable to read file %s", reqPath)
|
||||
// Check if the path matches the keys in the services map
|
||||
for route, handler := range a.services {
|
||||
if strings.HasPrefix(reqPath, route) {
|
||||
req.URL.Path = strings.TrimPrefix(reqPath, route)
|
||||
// Strip leading slash
|
||||
req.URL.Path = strings.TrimPrefix(req.URL.Path, "/")
|
||||
handler.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
a.writeBlob(rw, reqPath, file)
|
||||
} else {
|
||||
userHandler.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
// Check if it can be served by the user-provided handler
|
||||
if !strings.HasPrefix(reqPath, servicePrefix) {
|
||||
userHandler.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AssetServer) AttachServiceHandler(prefix string, handler http.Handler) {
|
||||
if a.services == nil {
|
||||
a.services = make(map[string]http.Handler)
|
||||
}
|
||||
a.services[prefix] = handler
|
||||
}
|
||||
|
||||
func (a *AssetServer) writeBlob(rw http.ResponseWriter, filename string, blob []byte) {
|
||||
err := ServeFile(rw, filename, blob)
|
||||
if err != nil {
|
||||
|
|
@ -159,30 +150,6 @@ func (a *AssetServer) serveError(rw http.ResponseWriter, err error, msg string,
|
|||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
//func (a *AssetServer) AddPluginScript(pluginName string, script string) {
|
||||
// if a.pluginScripts == nil {
|
||||
// a.pluginScripts = make(map[string]string)
|
||||
// }
|
||||
// pluginName = strings.ReplaceAll(pluginName, "/", "_")
|
||||
// pluginName = html.EscapeString(pluginName)
|
||||
// pluginScriptName := fmt.Sprintf("/wails/plugin/%s.js", pluginName)
|
||||
// a.pluginScripts[pluginScriptName] = script
|
||||
//}
|
||||
|
||||
func (a *AssetServer) AddPluginAssets(pluginPath string, vfs fs.FS) error {
|
||||
pluginPath = path.Join(pluginPrefix, pluginPath)
|
||||
_, exists := a.pluginAssets[pluginPath]
|
||||
if exists {
|
||||
return fmt.Errorf("plugin path already exists: %s", pluginPath)
|
||||
}
|
||||
if embedFs, isEmbedFs := vfs.(embed.FS); isEmbedFs {
|
||||
rootFolder, _ := findEmbedRootPath(embedFs)
|
||||
vfs, _ = fs.Sub(vfs, path.Clean(rootFolder))
|
||||
}
|
||||
a.pluginAssets[pluginPath] = vfs
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetStartURL(userURL string) (string, error) {
|
||||
devServerURL := GetDevServerURL()
|
||||
startURL := baseURL.String()
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package commands
|
|||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v3/internal/flags"
|
||||
"github.com/wailsapp/wails/v3/internal/plugins"
|
||||
"github.com/wailsapp/wails/v3/internal/service"
|
||||
"strings"
|
||||
|
||||
"github.com/pterm/pterm"
|
||||
|
|
@ -31,7 +31,7 @@ func toCamelCasePlugin(s string) string {
|
|||
return camelCase + "Plugin"
|
||||
}
|
||||
|
||||
func PluginInit(options *flags.PluginInit) error {
|
||||
func ServiceInit(options *flags.ServiceInit) error {
|
||||
|
||||
if options.Quiet {
|
||||
pterm.DisableOutput()
|
||||
|
|
@ -41,5 +41,5 @@ func PluginInit(options *flags.PluginInit) error {
|
|||
options.PackageName = toCamelCasePlugin(options.Name)
|
||||
}
|
||||
|
||||
return plugins.Install(options)
|
||||
return service.Install(options)
|
||||
}
|
||||
|
|
@ -1,9 +1,14 @@
|
|||
package flags
|
||||
|
||||
type PluginInit struct {
|
||||
type ServiceInit struct {
|
||||
Name string `name:"n" description:"Name of plugin" default:"example_plugin"`
|
||||
Description string `name:"d" description:"Description of plugin" default:"Example plugin"`
|
||||
PackageName string `name:"p" description:"Package name for plugin" default:""`
|
||||
OutputDir string `name:"o" description:"Output directory" default:"."`
|
||||
Quiet bool `name:"q" description:"Suppress output to console"`
|
||||
Author string `name:"a" description:"Author of plugin" default:""`
|
||||
Version string `name:"v" description:"Version of plugin" default:""`
|
||||
Website string `name:"w" description:"Website of plugin" default:""`
|
||||
Repository string `name:"r" description:"Repository of plugin" default:""`
|
||||
License string `name:"l" description:"License of plugin" default:""`
|
||||
}
|
||||
|
|
@ -120,7 +120,8 @@ func FindServices(pkgs []*packages.Package, systemPaths *config.SystemPaths, log
|
|||
if fn.Name() == "NewService" && fn.Pkg().Path() == systemPaths.ApplicationPackage {
|
||||
// Check signature.
|
||||
signature := fn.Type().(*types.Signature)
|
||||
if signature.Params().Len() != 1 || signature.Results().Len() != 1 || tp.Len() != 1 || tp.At(0).Obj() == nil {
|
||||
if signature.Params().Len() > 2 || signature.Results().Len() != 1 || tp.Len() != 1 || tp.At(0).Obj() == nil {
|
||||
logger.Warningf("Param Len: %d, Results Len: %d, tp.Len: %d, tp.At(0).Obj(): %v", signature.Params().Len(), signature.Results().Len(), tp.Len(), tp.At(0).Obj())
|
||||
return ErrBadApplicationPackage
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,22 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
func isInternalServiceMethod(method *types.Func) bool {
|
||||
internalServiceMethods := []string{
|
||||
"OnStartup",
|
||||
"OnShutdown",
|
||||
"ServeHTTP",
|
||||
}
|
||||
methodName := method.Name()
|
||||
for _, name := range internalServiceMethods {
|
||||
if name == methodName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func newServiceInfo(collector *Collector, obj *types.TypeName) *ServiceInfo {
|
||||
return &ServiceInfo{
|
||||
TypeInfo: collector.Type(obj),
|
||||
|
|
@ -171,6 +187,10 @@ var typeAny = types.Universe.Lookup("any").Type().Underlying()
|
|||
// collectMethod collects and returns information about a service method.
|
||||
// It is intended to be called only by ServiceInfo.Collect.
|
||||
func (info *ServiceInfo) collectMethod(method *types.Func) *ServiceMethodInfo {
|
||||
if isInternalServiceMethod(method) {
|
||||
// Ignore internal methods.
|
||||
return nil
|
||||
}
|
||||
collector := info.collector
|
||||
obj := info.Object().(*types.TypeName)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,82 +0,0 @@
|
|||
# Next Steps
|
||||
|
||||
Congratulations on generating a plugin. This guide will help you author your plugin
|
||||
and provide some tips on how to get started.
|
||||
|
||||
## Plugin Structure
|
||||
|
||||
The plugin is a standard Go module that adheres to the following interface:
|
||||
|
||||
```go
|
||||
type Plugin interface {
|
||||
Name() string
|
||||
Init(app *App) error
|
||||
Shutdown()
|
||||
}
|
||||
```
|
||||
|
||||
The `Name()` method returns the name of the plugin. It should follow the Go module naming convention
|
||||
and have a prefix of `wails-plugin-`, e.g. `github.com/myuser/wails-plugin-example`.
|
||||
|
||||
The `Init()` method is called when the plugin is loaded. The `App` parameter is a pointer to the
|
||||
main application struct. This may be used for showing dialogs, listening for events or even opening
|
||||
new windows. The `Init()` method should return an error if it fails to initialise. This method is
|
||||
called synchronously so the application will not start until it returns.
|
||||
|
||||
The `Shutdown()` method is called when the application is shutting down. This is a good place to
|
||||
perform any cleanup. This method is called synchronously so the application will not exit completely until
|
||||
it returns.
|
||||
|
||||
## Plugin Directory Structure
|
||||
|
||||
The plugin directory structure is as follows:
|
||||
|
||||
```
|
||||
plugin-name
|
||||
├── models.d.ts
|
||||
├── plugin.js
|
||||
├── plugin.go
|
||||
├── README.md
|
||||
├── go.mod
|
||||
├── go.sum
|
||||
└── plugin.toml
|
||||
```
|
||||
|
||||
### `plugin.go`
|
||||
|
||||
This file contains the plugin code. It should contain a struct that implements the `Plugin` interface
|
||||
and a `NewPlugin()` method that returns a pointer to the struct. Methods are exported by capitalising
|
||||
the first letter of the method name. These methods may be called from the frontend. If methods
|
||||
accept or return structs, these structs must be exported.
|
||||
|
||||
### `plugin.js`
|
||||
|
||||
This file should contain any JavaScript code that may help developers use the plugin.
|
||||
In the example plugin, this file contains function wrappers for the plugin methods.
|
||||
It's good to include JSDocs as that will help developers using your plugin.
|
||||
|
||||
### `models.d.ts`
|
||||
|
||||
This file should contain TypeScript definitions for any structs that are passed
|
||||
or returned from the plugin.
|
||||
`
|
||||
### `plugin.toml`
|
||||
|
||||
This file contains the plugin metadata. It is important to fill this out correctly
|
||||
as it will be used by the Wails CLI.
|
||||
|
||||
### `README.md`
|
||||
|
||||
This file should contain a description of the plugin and how to use it. It should
|
||||
also contain a link to the plugin repository and how to report bugs.
|
||||
|
||||
### `go.mod` and `go.sum`
|
||||
|
||||
These are standard Go module files. The package name in `go.mod` should match the
|
||||
name of the plugin, e.g. `github.com/myuser/wails-plugin-example`.
|
||||
|
||||
## Promoting your Plugin
|
||||
|
||||
Once you have created your plugin, you should promote it on the Wails Discord server
|
||||
in the `#plugins` channel. You should also open a PR to promote your plugin on the Wails
|
||||
website. Update the `website/content/plugins.md` file and add your plugin to the list.
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
# {{.Name}} Plugin
|
||||
|
||||
This example plugin provides a way to generate hashes of strings.
|
||||
|
||||
## Installation
|
||||
|
||||
Add the plugin to the `Plugins` option in the Applications options:
|
||||
|
||||
```go
|
||||
Plugins: map[string]application.Plugin{
|
||||
"{{.Name}}": {{.Name}}.NewPlugin(),
|
||||
},
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
You can then call the methods from the frontend:
|
||||
|
||||
```js
|
||||
wails.Plugin("{{.Name}}","All","hello world").then((result) => console.log(result))
|
||||
```
|
||||
|
||||
This method returns a struct with the following fields:
|
||||
|
||||
```typescript
|
||||
interface Hashes {
|
||||
MD5: string;
|
||||
SHA1: string;
|
||||
SHA256: string;
|
||||
}
|
||||
```
|
||||
|
||||
A TypeScript definition file is provided for this interface.
|
||||
|
||||
## Support
|
||||
|
||||
If you find a bug in this plugin, please raise a ticket [here](https://github.com/plugin/repository).
|
||||
Please do not contact the Wails team for support.
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
// models.d.ts
|
||||
// This file should contain any models that are used by the plugin.
|
||||
|
||||
export namespace {{.Name}}Plugin {
|
||||
export interface Hashes {
|
||||
MD5: string;
|
||||
SHA1: string;
|
||||
SHA256: string;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
package {{.Name}}
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
// ---------------- Plugin Setup ----------------
|
||||
// This is the main plugin struct. It can be named anything you like.
|
||||
// It must implement the application.Plugin interface.
|
||||
// Both the Init() and Shutdown() methods are called synchronously when the app starts and stops.
|
||||
|
||||
type Config struct {
|
||||
// Add any configuration options here
|
||||
}
|
||||
|
||||
type Plugin struct{
|
||||
config *Config
|
||||
app *application.App
|
||||
}
|
||||
|
||||
func NewPlugin(config *Config) *Plugin {
|
||||
return &Plugin{
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown is called when the app is shutting down
|
||||
// You can use this to clean up any resources you have allocated
|
||||
func (p *Plugin) Shutdown() {}
|
||||
|
||||
// Name returns the name of the plugin.
|
||||
// You should use the go module format e.g. github.com/myuser/myplugin
|
||||
func (p *Plugin) Name() string {
|
||||
return "github.com/myuser/{{.Name}}"
|
||||
}
|
||||
|
||||
// Init is called when the app is starting up. You can use this to
|
||||
// initialise any resources you need. You can also access the application
|
||||
// instance via the app property.
|
||||
func (p *Plugin) Init(app *application.App) error {
|
||||
p.app = app
|
||||
return nil
|
||||
}
|
||||
|
||||
// Exported returns a list of exported methods that can be called from the frontend
|
||||
func (p *Plugin) CallableByJS() []string {
|
||||
return []string{
|
||||
"Greet",
|
||||
}
|
||||
}
|
||||
|
||||
// InjectJS returns any JS that should be injected into the frontend
|
||||
func (p *Plugin) InjectJS() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// ---------------- Plugin Methods ----------------
|
||||
// Plugin methods are just normal Go methods. You can add as many as you like.
|
||||
// The only requirement is that they are exported (start with a capital letter).
|
||||
// You can also return any type that is JSON serializable.
|
||||
// Any methods that you want to be callable from the frontend must be returned by the
|
||||
// CallableByJS() method above.
|
||||
// See https://golang.org/pkg/encoding/json/#Marshal for more information.
|
||||
|
||||
func (p *Plugin) Greet(name string) string {
|
||||
return "Hello " + name
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
// plugin.js
|
||||
// This file should contain helper functions for the that can be used by the frontend.
|
||||
// Below are examples of how to use JSDoc to define the Hashes struct and the exported functions.
|
||||
|
||||
/**
|
||||
* @typedef {Object} Hashes - A collection of hashes.
|
||||
* @property {string} md5 - The MD5 hash of a string, represented as a hexadecimal string.
|
||||
* @property {string} sha1 - The SHA-1 hash of a string, represented as a hexadecimal string.
|
||||
* @property {string} sha256 - The SHA-256 hash of a string, represented as a hexadecimal string.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generate all hashes for a string.
|
||||
* @param input {string} - The string to generate hashes for.
|
||||
* @returns {Promise<Hashes>}
|
||||
*/
|
||||
export function All(input) {
|
||||
return wails.Plugin("{{.Name}}", "All", input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the MD5 hash for a string.
|
||||
* @param input {string} - The string to generate the hash for.
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
export function MD5(input) {
|
||||
return wails.Plugin("{{.Name}}", "MD5", input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SHA-1 hash for a string.
|
||||
* @param input {string} - The string to generate the hash for.
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
export function SHA1(input) {
|
||||
return wails.Plugin("{{.Name}}", "SHA1", input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SHA-256 hash for a string.
|
||||
* @param input {string} - The string to generate the hash for.
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
export function SHA256(input) {
|
||||
return wails.Plugin("{{.Name}}", "SHA256", input);
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
# This is the plugin definition file for the "{{.Name}}" plugin.
|
||||
|
||||
Name = "{{.Name}}"
|
||||
Description = "{{.Description}}"
|
||||
Author = ""
|
||||
Version = ""
|
||||
Website = ""
|
||||
Repository = ""
|
||||
License = ""
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package plugins
|
||||
package service
|
||||
|
||||
import (
|
||||
"embed"
|
||||
|
|
@ -15,19 +15,19 @@ import (
|
|||
)
|
||||
|
||||
//go:embed template
|
||||
var pluginTemplate embed.FS
|
||||
var serviceTemplate embed.FS
|
||||
|
||||
type TemplateOptions struct {
|
||||
*flags.PluginInit
|
||||
*flags.ServiceInit
|
||||
}
|
||||
|
||||
func Install(options *flags.PluginInit) error {
|
||||
func Install(options *flags.ServiceInit) error {
|
||||
|
||||
if options.OutputDir == "." || options.OutputDir == "" {
|
||||
options.OutputDir = filepath.Join(lo.Must(os.Getwd()), options.Name)
|
||||
}
|
||||
fmt.Printf("Creating plugin '%s' into '%s'\n", options.Name, options.OutputDir)
|
||||
tfs, err := fs.Sub(pluginTemplate, "template")
|
||||
fmt.Printf("Generating service '%s' into '%s'\n", options.Name, options.OutputDir)
|
||||
tfs, err := fs.Sub(serviceTemplate, "template")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
129
v3/internal/service/template/README.tmpl.md
Normal file
129
v3/internal/service/template/README.tmpl.md
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
# Wails v3 Service Template
|
||||
|
||||
This README provides an overview of the Wails v3 service template and explains how to adapt it to create your own custom service.
|
||||
|
||||
## Overview
|
||||
|
||||
The service template provides a basic structure for creating a Wails v3 service. A service in Wails v3 is a Go package that can be integrated into your Wails application to provide specific functionality, handle HTTP requests, and interact with the frontend.
|
||||
|
||||
## Template Structure
|
||||
|
||||
The template defines a `MyService` struct and several methods:
|
||||
|
||||
### MyService Struct
|
||||
|
||||
```go
|
||||
type MyService struct {
|
||||
ctx context.Context
|
||||
options application.ServiceOptions
|
||||
}
|
||||
```
|
||||
|
||||
This is the main service struct. You can rename it to better reflect your service's purpose. The struct holds a context and service options, which are set during startup.
|
||||
|
||||
### Name Method
|
||||
|
||||
```go
|
||||
func (p *MyService) Name() string
|
||||
```
|
||||
|
||||
This method returns the name of the service. It's used to identify the service within the Wails application.
|
||||
|
||||
### OnStartup Method
|
||||
|
||||
```go
|
||||
func (p *MyService) OnStartup(ctx context.Context, options application.ServiceOptions) error
|
||||
```
|
||||
|
||||
This method is called when the app is starting up. Use it to initialize resources, set up connections, or perform any necessary setup tasks.
|
||||
It receives a context and service options, which are stored in the service struct.
|
||||
|
||||
### OnShutdown Method
|
||||
|
||||
```go
|
||||
func (p *MyService) OnShutdown() error
|
||||
```
|
||||
|
||||
This method is called when the app is shutting down. Use it to clean up resources, close connections, or perform any necessary cleanup tasks.
|
||||
|
||||
### ServeHTTP Method
|
||||
|
||||
```go
|
||||
func (p *MyService) ServeHTTP(w http.ResponseWriter, r *http.Request)
|
||||
```
|
||||
|
||||
This method handles HTTP requests to the service. It's called when the frontend makes an HTTP request to the backend
|
||||
at the path specified in the `Route` field of the service options.
|
||||
|
||||
### Service Methods
|
||||
|
||||
```go
|
||||
func (p *MyService) Greet(name string) string
|
||||
```
|
||||
|
||||
This is an example of a service method. You can add as many methods as you need. These methods can be called from the frontend.
|
||||
|
||||
## Adapting the Template
|
||||
|
||||
To create your own service:
|
||||
|
||||
1. Rename the `MyService` struct to reflect your service's purpose (e.g., `DatabaseService`, `AuthService`).
|
||||
2. Update the `Name` method to return your service's unique identifier.
|
||||
3. Implement the `OnStartup` method to initialize your service. This might include setting up database connections, loading configuration, etc.
|
||||
4. If needed, implement the `OnShutdown` method to properly clean up resources when the application closes.
|
||||
5. If your service needs to handle HTTP requests, implement the `ServeHTTP` method. Use this to create API endpoints, serve files, or handle any HTTP interactions.
|
||||
6. Add your own methods to the service. These can include database operations, business logic, or any functionality your service needs to provide.
|
||||
7. If your service requires configuration, consider adding a `Config` struct and a `New` function to create and configure your service.
|
||||
|
||||
## Example: Database Service
|
||||
|
||||
Here's how you might adapt the template for a database service:
|
||||
|
||||
```go
|
||||
type DatabaseService struct {
|
||||
ctx context.Context
|
||||
options application.ServiceOptions
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func (s *DatabaseService) Name() string {
|
||||
return "github.com/myname/DatabaseService"
|
||||
}
|
||||
|
||||
func (s *DatabaseService) OnStartup(ctx context.Context, options application.ServiceOptions) error {
|
||||
s.ctx = ctx
|
||||
s.options = options
|
||||
// Initialize database connection
|
||||
var err error
|
||||
s.db, err = sql.Open("mysql", "user:password@/dbname")
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DatabaseService) OnShutdown() error {
|
||||
return s.db.Close()
|
||||
}
|
||||
|
||||
func (s *DatabaseService) GetUser(id int) (User, error) {
|
||||
// Implement database query
|
||||
}
|
||||
|
||||
// Add more methods as needed
|
||||
```
|
||||
|
||||
## Long-running tasks
|
||||
|
||||
If your service needs to perform long-running tasks, consider using goroutines and channels to manage these tasks.
|
||||
You can use the `context.Context` to listen for when the application shuts down:
|
||||
|
||||
```go
|
||||
func (s *DatabaseService) longRunningTask() {
|
||||
for {
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
// Cleanup and exit
|
||||
return
|
||||
// Perform long-running task
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
module {{.Name}}
|
||||
|
||||
go 1.20
|
||||
go 1.23
|
||||
|
||||
require github.com/wailsapp/wails/v3 v3.0.0-alpha.0
|
||||
require github.com/wailsapp/wails/v3 v3.0.0-alpha.4
|
||||
|
||||
require (
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
60
v3/internal/service/template/service.go.tmpl
Normal file
60
v3/internal/service/template/service.go.tmpl
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package {{.Name}}
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
// ---------------- Service Setup ----------------
|
||||
// This is the main service struct. It can be named anything you like.
|
||||
// Both the OnStartup() and OnShutdown() methods are called synchronously when the app starts and stops.
|
||||
// Changing the name of this struct will change the name of the services class in the frontend
|
||||
// Bound methods will exist inside frontend/bindings/github.com/user/{{.Name}} under the name of the struct
|
||||
type MyService struct{
|
||||
ctx context.Context
|
||||
options application.ServiceOptions
|
||||
}
|
||||
|
||||
// Name is the name of the service
|
||||
func (p *MyService) Name() string {
|
||||
return "{{.Name}}"
|
||||
}
|
||||
|
||||
// OnStartup is called when the app is starting up. You can use this to
|
||||
// initialise any resources you need. You can also access the application
|
||||
// instance via the app property.
|
||||
// OPTIONAL: This method is optional.
|
||||
func (p *MyService) OnStartup(ctx context.Context, options application.ServiceOptions) error {
|
||||
p.ctx = ctx
|
||||
p.options = options
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnShutdown is called when the app is shutting down via runtime.Quit() call
|
||||
// You can use this to clean up any resources you have allocated
|
||||
// OPTIONAL: This method is optional.
|
||||
func (p *MyService) OnShutdown() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServeHTTP is called when the app is running and the frontend makes an HTTP request to the backend at the path
|
||||
// specified in the `Route` field of the service Options.
|
||||
// OPTIONAL: This method is optional.
|
||||
func (p *MyService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// You can use the request to get the path, query parameters, headers, etc.
|
||||
// You can also use the response to set the status code, headers, body etc.
|
||||
// Consult the net/http documentation for more information: https://pkg.go.dev/net/http
|
||||
|
||||
// Log the request to the console
|
||||
log.Printf("Received request: %s %s", r.Method, r.URL.Path)
|
||||
}
|
||||
|
||||
// ---------------- Service Methods ----------------
|
||||
// Service methods are just normal Go methods. You can add as many as you like.
|
||||
// The only requirement is that they are exported (start with a capital letter).
|
||||
// You can also return any type that is JSON serializable.
|
||||
// See https://golang.org/pkg/encoding/json/#Marshal for more information.
|
||||
|
||||
func (p *MyService) Greet(name string) string {
|
||||
return "Hello " + name
|
||||
}
|
||||
8
v3/internal/service/template/service.tmpl.yml
Normal file
8
v3/internal/service/template/service.tmpl.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# This is the plugin definition file for the "{{.Name}}" plugin.
|
||||
Name: "{{.Name}}"
|
||||
Description: "{{.Description}}"
|
||||
Author: "{{.Author}}"
|
||||
Version: "{{.Version}}"
|
||||
Website: "{{.Website}}"
|
||||
Repository: "{{.Repository}}"
|
||||
License: "{{.License}}"
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
|
@ -135,18 +136,18 @@ func New(appOptions Options) *App {
|
|||
result.handleFatalError(fmt.Errorf("Fatal error in application initialisation: " + err.Error()))
|
||||
}
|
||||
|
||||
result.plugins = NewPluginManager(appOptions.Plugins, srv)
|
||||
errors := result.plugins.Init()
|
||||
if len(errors) > 0 {
|
||||
for _, err := range errors {
|
||||
result.handleError(fmt.Errorf("Error initialising plugin: " + err.Error()))
|
||||
for _, service := range appOptions.Services {
|
||||
if thisService, ok := service.instance.(ServiceStartup); ok {
|
||||
err := thisService.OnStartup(result.ctx, service.options)
|
||||
if err != nil {
|
||||
name := service.options.Name
|
||||
if name == "" {
|
||||
name = getServiceName(service)
|
||||
}
|
||||
globalApplication.error("OnStartup() failed:", "service", name, "error", err.Error())
|
||||
continue
|
||||
}
|
||||
}
|
||||
result.handleFatalError(fmt.Errorf("fatal error in plugins initialisation"))
|
||||
}
|
||||
|
||||
err = result.bindings.AddPlugins(appOptions.Plugins)
|
||||
if err != nil {
|
||||
result.handleFatalError(fmt.Errorf("Fatal error in application initialisation: " + err.Error()))
|
||||
}
|
||||
|
||||
// Process keybindings
|
||||
|
|
@ -267,6 +268,8 @@ type eventHook struct {
|
|||
}
|
||||
|
||||
type App struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
options Options
|
||||
applicationEventListeners map[uint][]*EventListener
|
||||
applicationEventListenersLock sync.RWMutex
|
||||
|
|
@ -293,7 +296,6 @@ type App struct {
|
|||
pendingRun []runnable
|
||||
|
||||
bindings *Bindings
|
||||
plugins *PluginManager
|
||||
|
||||
// platform app
|
||||
impl platformApp
|
||||
|
|
@ -361,6 +363,7 @@ func (a *App) handleFatalError(err error) {
|
|||
}
|
||||
|
||||
func (a *App) init() {
|
||||
a.ctx, a.cancel = context.WithCancel(context.Background())
|
||||
a.applicationEventHooks = make(map[uint][]*eventHook)
|
||||
a.applicationEventListeners = make(map[uint][]*EventListener)
|
||||
a.windows = make(map[uint]Window)
|
||||
|
|
@ -440,6 +443,10 @@ func (a *App) RegisterListener(listener WailsEventListener) {
|
|||
a.wailsEventListenerLock.Unlock()
|
||||
}
|
||||
|
||||
func (a *App) RegisterServiceHandler(prefix string, handler http.Handler) {
|
||||
a.assets.AttachServiceHandler(prefix, handler)
|
||||
}
|
||||
|
||||
func (a *App) NewWebviewWindow() *WebviewWindow {
|
||||
return a.NewWebviewWindowWithOptions(WebviewWindowOptions{})
|
||||
}
|
||||
|
|
@ -579,10 +586,16 @@ func (a *App) Run() error {
|
|||
return err
|
||||
}
|
||||
|
||||
errors := a.plugins.Shutdown()
|
||||
if len(errors) > 0 {
|
||||
for _, err := range errors {
|
||||
a.error("Error shutting down plugin: " + err.Error())
|
||||
// Cancel the context
|
||||
a.cancel()
|
||||
|
||||
for _, service := range a.options.Services {
|
||||
// If it conforms to the ServiceShutdown interface, call the Shutdown method
|
||||
if thisService, ok := service.instance.(ServiceShutdown); ok {
|
||||
err := thisService.OnShutdown()
|
||||
if err != nil {
|
||||
a.error("Error shutting down service: " + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,12 +13,29 @@ import (
|
|||
// Valid values may only be obtained by calling [NewService].
|
||||
type Service struct {
|
||||
instance any
|
||||
options ServiceOptions
|
||||
}
|
||||
|
||||
type ServiceOptions struct {
|
||||
// Name can be set to override the name of the service
|
||||
// This is useful for logging and debugging purposes
|
||||
Name string
|
||||
// Route is the path to the assets
|
||||
Route string
|
||||
}
|
||||
|
||||
var DefaultServiceOptions = ServiceOptions{
|
||||
Route: "",
|
||||
}
|
||||
|
||||
// NewService returns a Service value wrapping the given pointer.
|
||||
// If T is not a named type, the returned value is invalid.
|
||||
func NewService[T any](instance *T) Service {
|
||||
return Service{instance}
|
||||
// The prefix is used if Service implements a http.Handler only one allowed
|
||||
func NewService[T any](instance *T, options ...ServiceOptions) Service {
|
||||
if len(options) == 1 {
|
||||
return Service{instance, options[0]}
|
||||
}
|
||||
return Service{instance, DefaultServiceOptions}
|
||||
}
|
||||
|
||||
func (s Service) Instance() any {
|
||||
|
|
@ -62,9 +79,6 @@ type Options struct {
|
|||
// Assets are the application assets to be used.
|
||||
Assets AssetOptions
|
||||
|
||||
// Plugins is a map of plugins used by the application
|
||||
Plugins map[string]Plugin
|
||||
|
||||
// Flags are key value pairs that are available to the frontend.
|
||||
// This is also used by Wails to provide information to the frontend.
|
||||
Flags map[string]any
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
|
@ -79,12 +80,17 @@ type Bindings struct {
|
|||
}
|
||||
|
||||
func NewBindings(instances []Service, aliases map[uint32]uint32) (*Bindings, error) {
|
||||
app := Get()
|
||||
b := &Bindings{
|
||||
boundMethods: make(map[string]*BoundMethod),
|
||||
boundByID: make(map[uint32]*BoundMethod),
|
||||
methodAliases: aliases,
|
||||
}
|
||||
for _, binding := range instances {
|
||||
handler, ok := binding.Instance().(http.Handler)
|
||||
if ok && binding.options.Route != "" {
|
||||
app.assets.AttachServiceHandler(binding.options.Route, handler)
|
||||
}
|
||||
err := b.Add(binding.Instance())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -108,34 +114,6 @@ func (b *Bindings) Add(namedPtr interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (b *Bindings) AddPlugins(plugins map[string]Plugin) error {
|
||||
for pluginID, plugin := range plugins {
|
||||
methods, err := b.getMethods(plugin, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot add plugin '%s' to app: %s", pluginID, err.Error())
|
||||
}
|
||||
|
||||
exportedMethods := plugin.CallableByJS()
|
||||
|
||||
for _, method := range methods {
|
||||
// Do not expose reserved methods
|
||||
if lo.Contains(reservedPluginMethods, method.Name) {
|
||||
continue
|
||||
}
|
||||
// Do not expose methods that are not in the exported list
|
||||
if !lo.Contains(exportedMethods, method.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Add it as a regular method
|
||||
b.boundMethods[fmt.Sprintf("wails-plugins.%s.%s", pluginID, method.Name)] = method
|
||||
b.boundByID[method.ID] = method
|
||||
globalApplication.debug("Added plugin method: "+pluginID+"."+method.Name, "id", method.ID)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the bound method with the given name
|
||||
func (b *Bindings) Get(options *CallOptions) *BoundMethod {
|
||||
method, ok := b.boundMethods[options.MethodName]
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ const (
|
|||
)
|
||||
|
||||
type MessageProcessor struct {
|
||||
pluginManager *PluginManager
|
||||
logger *slog.Logger
|
||||
|
||||
runningCalls map[string]context.CancelFunc
|
||||
|
|
|
|||
|
|
@ -1,67 +0,0 @@
|
|||
package application
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wailsapp/wails/v3/internal/assetserver"
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
type PluginAPI interface {
|
||||
}
|
||||
|
||||
type Plugin interface {
|
||||
Name() string
|
||||
Init(api PluginAPI) error
|
||||
Shutdown() error
|
||||
CallableByJS() []string
|
||||
Assets() fs.FS
|
||||
}
|
||||
|
||||
type PluginManager struct {
|
||||
plugins map[string]Plugin
|
||||
assetServer *assetserver.AssetServer
|
||||
initialisedPlugins []Plugin
|
||||
}
|
||||
|
||||
func NewPluginManager(plugins map[string]Plugin, assetServer *assetserver.AssetServer) *PluginManager {
|
||||
result := &PluginManager{
|
||||
plugins: plugins,
|
||||
assetServer: assetServer,
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (p *PluginManager) Init() []error {
|
||||
|
||||
api := newPluginAPI()
|
||||
for id, plugin := range p.plugins {
|
||||
err := plugin.Init(api)
|
||||
if err != nil {
|
||||
globalApplication.error("Plugin '%s' failed to initialise: %s", plugin.Name(), err.Error())
|
||||
return p.Shutdown()
|
||||
}
|
||||
p.initialisedPlugins = append(p.initialisedPlugins, plugin)
|
||||
assets := plugin.Assets()
|
||||
if assets != nil {
|
||||
err = p.assetServer.AddPluginAssets(id, assets)
|
||||
if err != nil {
|
||||
return []error{errors.Wrap(err, "Failed to add plugin assets: "+plugin.Name())}
|
||||
}
|
||||
}
|
||||
globalApplication.debug("Plugin initialised: " + plugin.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PluginManager) Shutdown() []error {
|
||||
var errs []error
|
||||
for _, plugin := range p.initialisedPlugins {
|
||||
err := plugin.Shutdown()
|
||||
globalApplication.debug("Plugin shutdown: " + plugin.Name())
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "Plugin failed to shutdown: "+plugin.Name())
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package application
|
||||
|
||||
type pluginAPI struct{}
|
||||
|
||||
func newPluginAPI() *pluginAPI {
|
||||
return &pluginAPI{}
|
||||
}
|
||||
27
v3/pkg/application/services.go
Normal file
27
v3/pkg/application/services.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type ServiceName interface {
|
||||
Name() string
|
||||
}
|
||||
|
||||
type ServiceStartup interface {
|
||||
OnStartup(ctx context.Context, options ServiceOptions) error
|
||||
}
|
||||
|
||||
type ServiceShutdown interface {
|
||||
OnShutdown() error
|
||||
}
|
||||
|
||||
func getServiceName(service any) string {
|
||||
// First check it conforms to ServiceName interface
|
||||
if serviceName, ok := service.(ServiceName); ok {
|
||||
return serviceName.Name()
|
||||
}
|
||||
// Next, get the name from the type
|
||||
return reflect.TypeOf(service).String()
|
||||
}
|
||||
|
|
@ -1,29 +1,29 @@
|
|||
package events
|
||||
|
||||
type ApplicationEventType uint
|
||||
type WindowEventType uint
|
||||
type WindowEventType uint
|
||||
|
||||
var Common = newCommonEvents()
|
||||
|
||||
type commonEvents struct {
|
||||
ApplicationStarted ApplicationEventType
|
||||
WindowMaximise WindowEventType
|
||||
WindowUnMaximise WindowEventType
|
||||
WindowFullscreen WindowEventType
|
||||
WindowMaximise WindowEventType
|
||||
WindowUnMaximise WindowEventType
|
||||
WindowFullscreen WindowEventType
|
||||
WindowUnFullscreen WindowEventType
|
||||
WindowRestore WindowEventType
|
||||
WindowMinimise WindowEventType
|
||||
WindowUnMinimise WindowEventType
|
||||
WindowClosing WindowEventType
|
||||
WindowZoom WindowEventType
|
||||
WindowZoomIn WindowEventType
|
||||
WindowZoomOut WindowEventType
|
||||
WindowZoomReset WindowEventType
|
||||
WindowFocus WindowEventType
|
||||
WindowLostFocus WindowEventType
|
||||
WindowShow WindowEventType
|
||||
WindowHide WindowEventType
|
||||
WindowDPIChanged WindowEventType
|
||||
WindowRestore WindowEventType
|
||||
WindowMinimise WindowEventType
|
||||
WindowUnMinimise WindowEventType
|
||||
WindowClosing WindowEventType
|
||||
WindowZoom WindowEventType
|
||||
WindowZoomIn WindowEventType
|
||||
WindowZoomOut WindowEventType
|
||||
WindowZoomReset WindowEventType
|
||||
WindowFocus WindowEventType
|
||||
WindowLostFocus WindowEventType
|
||||
WindowShow WindowEventType
|
||||
WindowHide WindowEventType
|
||||
WindowDPIChanged WindowEventType
|
||||
WindowFilesDropped WindowEventType
|
||||
WindowRuntimeReady WindowEventType
|
||||
ThemeChanged ApplicationEventType
|
||||
|
|
@ -88,130 +88,130 @@ func newLinuxEvents() linuxEvents {
|
|||
var Mac = newMacEvents()
|
||||
|
||||
type macEvents struct {
|
||||
ApplicationDidBecomeActive ApplicationEventType
|
||||
ApplicationDidChangeBackingProperties ApplicationEventType
|
||||
ApplicationDidChangeEffectiveAppearance ApplicationEventType
|
||||
ApplicationDidChangeIcon ApplicationEventType
|
||||
ApplicationDidChangeOcclusionState ApplicationEventType
|
||||
ApplicationDidChangeScreenParameters ApplicationEventType
|
||||
ApplicationDidChangeStatusBarFrame ApplicationEventType
|
||||
ApplicationDidChangeStatusBarOrientation ApplicationEventType
|
||||
ApplicationDidFinishLaunching ApplicationEventType
|
||||
ApplicationDidHide ApplicationEventType
|
||||
ApplicationDidResignActiveNotification ApplicationEventType
|
||||
ApplicationDidUnhide ApplicationEventType
|
||||
ApplicationDidUpdate ApplicationEventType
|
||||
ApplicationWillBecomeActive ApplicationEventType
|
||||
ApplicationWillFinishLaunching ApplicationEventType
|
||||
ApplicationWillHide ApplicationEventType
|
||||
ApplicationWillResignActive ApplicationEventType
|
||||
ApplicationWillTerminate ApplicationEventType
|
||||
ApplicationWillUnhide ApplicationEventType
|
||||
ApplicationWillUpdate ApplicationEventType
|
||||
ApplicationDidChangeTheme ApplicationEventType
|
||||
ApplicationShouldHandleReopen ApplicationEventType
|
||||
WindowDidBecomeKey WindowEventType
|
||||
WindowDidBecomeMain WindowEventType
|
||||
WindowDidBeginSheet WindowEventType
|
||||
WindowDidChangeAlpha WindowEventType
|
||||
WindowDidChangeBackingLocation WindowEventType
|
||||
WindowDidChangeBackingProperties WindowEventType
|
||||
WindowDidChangeCollectionBehavior WindowEventType
|
||||
WindowDidChangeEffectiveAppearance WindowEventType
|
||||
WindowDidChangeOcclusionState WindowEventType
|
||||
WindowDidChangeOrderingMode WindowEventType
|
||||
WindowDidChangeScreen WindowEventType
|
||||
WindowDidChangeScreenParameters WindowEventType
|
||||
WindowDidChangeScreenProfile WindowEventType
|
||||
WindowDidChangeScreenSpace WindowEventType
|
||||
WindowDidChangeScreenSpaceProperties WindowEventType
|
||||
WindowDidChangeSharingType WindowEventType
|
||||
WindowDidChangeSpace WindowEventType
|
||||
WindowDidChangeSpaceOrderingMode WindowEventType
|
||||
WindowDidChangeTitle WindowEventType
|
||||
WindowDidChangeToolbar WindowEventType
|
||||
WindowDidChangeVisibility WindowEventType
|
||||
WindowDidDeminiaturize WindowEventType
|
||||
WindowDidEndSheet WindowEventType
|
||||
WindowDidEnterFullScreen WindowEventType
|
||||
WindowDidEnterVersionBrowser WindowEventType
|
||||
WindowDidExitFullScreen WindowEventType
|
||||
WindowDidExitVersionBrowser WindowEventType
|
||||
WindowDidExpose WindowEventType
|
||||
WindowDidFocus WindowEventType
|
||||
WindowDidMiniaturize WindowEventType
|
||||
WindowDidMove WindowEventType
|
||||
WindowDidOrderOffScreen WindowEventType
|
||||
WindowDidOrderOnScreen WindowEventType
|
||||
WindowDidResignKey WindowEventType
|
||||
WindowDidResignMain WindowEventType
|
||||
WindowDidResize WindowEventType
|
||||
WindowDidUpdate WindowEventType
|
||||
WindowDidUpdateAlpha WindowEventType
|
||||
WindowDidUpdateCollectionBehavior WindowEventType
|
||||
WindowDidUpdateCollectionProperties WindowEventType
|
||||
WindowDidUpdateShadow WindowEventType
|
||||
WindowDidUpdateTitle WindowEventType
|
||||
WindowDidUpdateToolbar WindowEventType
|
||||
WindowDidUpdateVisibility WindowEventType
|
||||
WindowShouldClose WindowEventType
|
||||
WindowWillBecomeKey WindowEventType
|
||||
WindowWillBecomeMain WindowEventType
|
||||
WindowWillBeginSheet WindowEventType
|
||||
WindowWillChangeOrderingMode WindowEventType
|
||||
WindowWillClose WindowEventType
|
||||
WindowWillDeminiaturize WindowEventType
|
||||
WindowWillEnterFullScreen WindowEventType
|
||||
WindowWillEnterVersionBrowser WindowEventType
|
||||
WindowWillExitFullScreen WindowEventType
|
||||
WindowWillExitVersionBrowser WindowEventType
|
||||
WindowWillFocus WindowEventType
|
||||
WindowWillMiniaturize WindowEventType
|
||||
WindowWillMove WindowEventType
|
||||
WindowWillOrderOffScreen WindowEventType
|
||||
WindowWillOrderOnScreen WindowEventType
|
||||
WindowWillResignMain WindowEventType
|
||||
WindowWillResize WindowEventType
|
||||
WindowWillUnfocus WindowEventType
|
||||
WindowWillUpdate WindowEventType
|
||||
WindowWillUpdateAlpha WindowEventType
|
||||
WindowWillUpdateCollectionBehavior WindowEventType
|
||||
WindowWillUpdateCollectionProperties WindowEventType
|
||||
WindowWillUpdateShadow WindowEventType
|
||||
WindowWillUpdateTitle WindowEventType
|
||||
WindowWillUpdateToolbar WindowEventType
|
||||
WindowWillUpdateVisibility WindowEventType
|
||||
WindowWillUseStandardFrame WindowEventType
|
||||
MenuWillOpen ApplicationEventType
|
||||
MenuDidOpen ApplicationEventType
|
||||
MenuDidClose ApplicationEventType
|
||||
MenuWillSendAction ApplicationEventType
|
||||
MenuDidSendAction ApplicationEventType
|
||||
MenuWillHighlightItem ApplicationEventType
|
||||
MenuDidHighlightItem ApplicationEventType
|
||||
MenuWillDisplayItem ApplicationEventType
|
||||
MenuDidDisplayItem ApplicationEventType
|
||||
MenuWillAddItem ApplicationEventType
|
||||
MenuDidAddItem ApplicationEventType
|
||||
MenuWillRemoveItem ApplicationEventType
|
||||
MenuDidRemoveItem ApplicationEventType
|
||||
MenuWillBeginTracking ApplicationEventType
|
||||
MenuDidBeginTracking ApplicationEventType
|
||||
MenuWillEndTracking ApplicationEventType
|
||||
MenuDidEndTracking ApplicationEventType
|
||||
MenuWillUpdate ApplicationEventType
|
||||
MenuDidUpdate ApplicationEventType
|
||||
MenuWillPopUp ApplicationEventType
|
||||
MenuDidPopUp ApplicationEventType
|
||||
MenuWillSendActionToItem ApplicationEventType
|
||||
MenuDidSendActionToItem ApplicationEventType
|
||||
WebViewDidStartProvisionalNavigation WindowEventType
|
||||
ApplicationDidBecomeActive ApplicationEventType
|
||||
ApplicationDidChangeBackingProperties ApplicationEventType
|
||||
ApplicationDidChangeEffectiveAppearance ApplicationEventType
|
||||
ApplicationDidChangeIcon ApplicationEventType
|
||||
ApplicationDidChangeOcclusionState ApplicationEventType
|
||||
ApplicationDidChangeScreenParameters ApplicationEventType
|
||||
ApplicationDidChangeStatusBarFrame ApplicationEventType
|
||||
ApplicationDidChangeStatusBarOrientation ApplicationEventType
|
||||
ApplicationDidFinishLaunching ApplicationEventType
|
||||
ApplicationDidHide ApplicationEventType
|
||||
ApplicationDidResignActiveNotification ApplicationEventType
|
||||
ApplicationDidUnhide ApplicationEventType
|
||||
ApplicationDidUpdate ApplicationEventType
|
||||
ApplicationWillBecomeActive ApplicationEventType
|
||||
ApplicationWillFinishLaunching ApplicationEventType
|
||||
ApplicationWillHide ApplicationEventType
|
||||
ApplicationWillResignActive ApplicationEventType
|
||||
ApplicationWillTerminate ApplicationEventType
|
||||
ApplicationWillUnhide ApplicationEventType
|
||||
ApplicationWillUpdate ApplicationEventType
|
||||
ApplicationDidChangeTheme ApplicationEventType
|
||||
ApplicationShouldHandleReopen ApplicationEventType
|
||||
WindowDidBecomeKey WindowEventType
|
||||
WindowDidBecomeMain WindowEventType
|
||||
WindowDidBeginSheet WindowEventType
|
||||
WindowDidChangeAlpha WindowEventType
|
||||
WindowDidChangeBackingLocation WindowEventType
|
||||
WindowDidChangeBackingProperties WindowEventType
|
||||
WindowDidChangeCollectionBehavior WindowEventType
|
||||
WindowDidChangeEffectiveAppearance WindowEventType
|
||||
WindowDidChangeOcclusionState WindowEventType
|
||||
WindowDidChangeOrderingMode WindowEventType
|
||||
WindowDidChangeScreen WindowEventType
|
||||
WindowDidChangeScreenParameters WindowEventType
|
||||
WindowDidChangeScreenProfile WindowEventType
|
||||
WindowDidChangeScreenSpace WindowEventType
|
||||
WindowDidChangeScreenSpaceProperties WindowEventType
|
||||
WindowDidChangeSharingType WindowEventType
|
||||
WindowDidChangeSpace WindowEventType
|
||||
WindowDidChangeSpaceOrderingMode WindowEventType
|
||||
WindowDidChangeTitle WindowEventType
|
||||
WindowDidChangeToolbar WindowEventType
|
||||
WindowDidChangeVisibility WindowEventType
|
||||
WindowDidDeminiaturize WindowEventType
|
||||
WindowDidEndSheet WindowEventType
|
||||
WindowDidEnterFullScreen WindowEventType
|
||||
WindowDidEnterVersionBrowser WindowEventType
|
||||
WindowDidExitFullScreen WindowEventType
|
||||
WindowDidExitVersionBrowser WindowEventType
|
||||
WindowDidExpose WindowEventType
|
||||
WindowDidFocus WindowEventType
|
||||
WindowDidMiniaturize WindowEventType
|
||||
WindowDidMove WindowEventType
|
||||
WindowDidOrderOffScreen WindowEventType
|
||||
WindowDidOrderOnScreen WindowEventType
|
||||
WindowDidResignKey WindowEventType
|
||||
WindowDidResignMain WindowEventType
|
||||
WindowDidResize WindowEventType
|
||||
WindowDidUpdate WindowEventType
|
||||
WindowDidUpdateAlpha WindowEventType
|
||||
WindowDidUpdateCollectionBehavior WindowEventType
|
||||
WindowDidUpdateCollectionProperties WindowEventType
|
||||
WindowDidUpdateShadow WindowEventType
|
||||
WindowDidUpdateTitle WindowEventType
|
||||
WindowDidUpdateToolbar WindowEventType
|
||||
WindowDidUpdateVisibility WindowEventType
|
||||
WindowShouldClose WindowEventType
|
||||
WindowWillBecomeKey WindowEventType
|
||||
WindowWillBecomeMain WindowEventType
|
||||
WindowWillBeginSheet WindowEventType
|
||||
WindowWillChangeOrderingMode WindowEventType
|
||||
WindowWillClose WindowEventType
|
||||
WindowWillDeminiaturize WindowEventType
|
||||
WindowWillEnterFullScreen WindowEventType
|
||||
WindowWillEnterVersionBrowser WindowEventType
|
||||
WindowWillExitFullScreen WindowEventType
|
||||
WindowWillExitVersionBrowser WindowEventType
|
||||
WindowWillFocus WindowEventType
|
||||
WindowWillMiniaturize WindowEventType
|
||||
WindowWillMove WindowEventType
|
||||
WindowWillOrderOffScreen WindowEventType
|
||||
WindowWillOrderOnScreen WindowEventType
|
||||
WindowWillResignMain WindowEventType
|
||||
WindowWillResize WindowEventType
|
||||
WindowWillUnfocus WindowEventType
|
||||
WindowWillUpdate WindowEventType
|
||||
WindowWillUpdateAlpha WindowEventType
|
||||
WindowWillUpdateCollectionBehavior WindowEventType
|
||||
WindowWillUpdateCollectionProperties WindowEventType
|
||||
WindowWillUpdateShadow WindowEventType
|
||||
WindowWillUpdateTitle WindowEventType
|
||||
WindowWillUpdateToolbar WindowEventType
|
||||
WindowWillUpdateVisibility WindowEventType
|
||||
WindowWillUseStandardFrame WindowEventType
|
||||
MenuWillOpen ApplicationEventType
|
||||
MenuDidOpen ApplicationEventType
|
||||
MenuDidClose ApplicationEventType
|
||||
MenuWillSendAction ApplicationEventType
|
||||
MenuDidSendAction ApplicationEventType
|
||||
MenuWillHighlightItem ApplicationEventType
|
||||
MenuDidHighlightItem ApplicationEventType
|
||||
MenuWillDisplayItem ApplicationEventType
|
||||
MenuDidDisplayItem ApplicationEventType
|
||||
MenuWillAddItem ApplicationEventType
|
||||
MenuDidAddItem ApplicationEventType
|
||||
MenuWillRemoveItem ApplicationEventType
|
||||
MenuDidRemoveItem ApplicationEventType
|
||||
MenuWillBeginTracking ApplicationEventType
|
||||
MenuDidBeginTracking ApplicationEventType
|
||||
MenuWillEndTracking ApplicationEventType
|
||||
MenuDidEndTracking ApplicationEventType
|
||||
MenuWillUpdate ApplicationEventType
|
||||
MenuDidUpdate ApplicationEventType
|
||||
MenuWillPopUp ApplicationEventType
|
||||
MenuDidPopUp ApplicationEventType
|
||||
MenuWillSendActionToItem ApplicationEventType
|
||||
MenuDidSendActionToItem ApplicationEventType
|
||||
WebViewDidStartProvisionalNavigation WindowEventType
|
||||
WebViewDidReceiveServerRedirectForProvisionalNavigation WindowEventType
|
||||
WebViewDidFinishNavigation WindowEventType
|
||||
WebViewDidCommitNavigation WindowEventType
|
||||
WindowFileDraggingEntered WindowEventType
|
||||
WindowFileDraggingPerformed WindowEventType
|
||||
WindowFileDraggingExited WindowEventType
|
||||
WebViewDidFinishNavigation WindowEventType
|
||||
WebViewDidCommitNavigation WindowEventType
|
||||
WindowFileDraggingEntered WindowEventType
|
||||
WindowFileDraggingPerformed WindowEventType
|
||||
WindowFileDraggingExited WindowEventType
|
||||
}
|
||||
|
||||
func newMacEvents() macEvents {
|
||||
|
|
@ -346,13 +346,13 @@ func newMacEvents() macEvents {
|
|||
var Windows = newWindowsEvents()
|
||||
|
||||
type windowsEvents struct {
|
||||
SystemThemeChanged ApplicationEventType
|
||||
APMPowerStatusChange ApplicationEventType
|
||||
APMSuspend ApplicationEventType
|
||||
APMResumeAutomatic ApplicationEventType
|
||||
APMResumeSuspend ApplicationEventType
|
||||
APMPowerSettingChange ApplicationEventType
|
||||
ApplicationStarted ApplicationEventType
|
||||
SystemThemeChanged ApplicationEventType
|
||||
APMPowerStatusChange ApplicationEventType
|
||||
APMSuspend ApplicationEventType
|
||||
APMResumeAutomatic ApplicationEventType
|
||||
APMResumeSuspend ApplicationEventType
|
||||
APMPowerSettingChange ApplicationEventType
|
||||
ApplicationStarted ApplicationEventType
|
||||
WebViewNavigationCompleted WindowEventType
|
||||
WindowInactive WindowEventType
|
||||
WindowActive WindowEventType
|
||||
|
|
@ -595,4 +595,3 @@ var eventToJS = map[uint]string{
|
|||
1204: "common:WindowDidMove",
|
||||
1205: "common:WindowDidResize",
|
||||
}
|
||||
|
||||
|
|
|
|||
52
v3/pkg/services/fileserver/fileserver.go
Normal file
52
v3/pkg/services/fileserver/fileserver.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package fileserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
// ---------------- Service Setup ----------------
|
||||
// This is the main Service struct. It can be named anything you like.
|
||||
|
||||
type Config struct {
|
||||
RootPath string
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
config *Config
|
||||
fs http.Handler
|
||||
}
|
||||
|
||||
func New(config *Config) *Service {
|
||||
return &Service{
|
||||
config: config,
|
||||
fs: http.FileServer(http.Dir(config.RootPath)),
|
||||
}
|
||||
}
|
||||
|
||||
// OnShutdown is called when the app is shutting down
|
||||
// You can use this to clean up any resources you have allocated
|
||||
func (s *Service) OnShutdown() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name returns the name of the plugin.
|
||||
// You should use the go module format e.g. github.com/myuser/myplugin
|
||||
func (s *Service) Name() string {
|
||||
return "github.com/wailsapp/wails/v3/services/fileserver"
|
||||
}
|
||||
|
||||
// OnStartup is called when the app is starting up. You can use this to
|
||||
// initialise any resources you need.
|
||||
func (s *Service) OnStartup(ctx context.Context, options application.ServiceOptions) error {
|
||||
// Any initialization code here
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Create a new file server rooted at the given path
|
||||
// Strip the base path out of the request path
|
||||
s.fs.ServeHTTP(w, r)
|
||||
}
|
||||
|
|
@ -1,18 +1,15 @@
|
|||
package kvstore
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
//go:embed assets/*
|
||||
var assets embed.FS
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
type KeyValueStore struct {
|
||||
config *Config
|
||||
|
|
@ -27,17 +24,17 @@ type Config struct {
|
|||
AutoSave bool
|
||||
}
|
||||
|
||||
type Plugin struct{}
|
||||
type Service struct{}
|
||||
|
||||
func NewPlugin(config *Config) *KeyValueStore {
|
||||
func New(config *Config) *KeyValueStore {
|
||||
return &KeyValueStore{
|
||||
config: config,
|
||||
data: make(map[string]any),
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown will save the store to disk if there are unsaved changes.
|
||||
func (kvs *KeyValueStore) Shutdown() error {
|
||||
// OnShutdown will save the store to disk if there are unsaved changes.
|
||||
func (kvs *KeyValueStore) OnShutdown() error {
|
||||
if kvs.unsaved {
|
||||
err := kvs.Save()
|
||||
if err != nil {
|
||||
|
|
@ -52,9 +49,8 @@ func (kvs *KeyValueStore) Name() string {
|
|||
return "github.com/wailsapp/wails/v3/plugins/kvstore"
|
||||
}
|
||||
|
||||
// Init is called when the plugin is loaded. It is passed the application.App
|
||||
// instance. This is where you should do any setup.
|
||||
func (kvs *KeyValueStore) Init(api application.PluginAPI) error {
|
||||
// OnStartup is called when the plugin is loaded. This is where you should do any setup.
|
||||
func (kvs *KeyValueStore) OnStartup(ctx context.Context, options application.ServiceOptions) error {
|
||||
err := kvs.open(kvs.config.Filename)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -63,21 +59,6 @@ func (kvs *KeyValueStore) Init(api application.PluginAPI) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (kvs *KeyValueStore) CallableByJS() []string {
|
||||
return []string{
|
||||
"Set",
|
||||
"Get",
|
||||
"Delete",
|
||||
"Save",
|
||||
}
|
||||
}
|
||||
|
||||
func (kvs *KeyValueStore) Assets() fs.FS {
|
||||
return assets
|
||||
}
|
||||
|
||||
// ---------------- Plugin Methods ----------------
|
||||
|
||||
func (kvs *KeyValueStore) open(filename string) (err error) {
|
||||
kvs.filename = filename
|
||||
kvs.data = make(map[string]any)
|
||||
77
v3/pkg/services/log/log.go
Normal file
77
v3/pkg/services/log/log.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"log/slog"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
// Logger is the logger to use. If not set, a default logger will be used.
|
||||
Logger *slog.Logger
|
||||
|
||||
// LogLevel defines the log level of the logger.
|
||||
LogLevel slog.Level
|
||||
|
||||
// Handles errors that occur when writing to the log
|
||||
ErrorHandler func(err error)
|
||||
}
|
||||
|
||||
type LoggerService struct {
|
||||
config *Config
|
||||
app *application.App
|
||||
level slog.LevelVar
|
||||
}
|
||||
|
||||
func NewLoggerService(config *Config) *LoggerService {
|
||||
if config.Logger == nil {
|
||||
config.Logger = application.DefaultLogger(config.LogLevel)
|
||||
}
|
||||
|
||||
result := &LoggerService{
|
||||
config: config,
|
||||
}
|
||||
result.level.Set(config.LogLevel)
|
||||
return result
|
||||
}
|
||||
|
||||
func New() *LoggerService {
|
||||
return NewLoggerService(&Config{})
|
||||
}
|
||||
|
||||
// OnShutdown is called when the app is shutting down
|
||||
// You can use this to clean up any resources you have allocated
|
||||
func (l *LoggerService) OnShutdown() error { return nil }
|
||||
|
||||
// Name returns the name of the plugin.
|
||||
// You should use the go module format e.g. github.com/myuser/myplugin
|
||||
func (l *LoggerService) Name() string {
|
||||
return "github.com/wailsapp/wails/v3/plugins/log"
|
||||
}
|
||||
|
||||
func (l *LoggerService) OnStartup(ctx context.Context, options application.ServiceOptions) error {
|
||||
// Any initialization code here
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LoggerService) Debug(message string, args ...any) {
|
||||
l.config.Logger.Debug(message, args...)
|
||||
}
|
||||
|
||||
func (l *LoggerService) Info(message string, args ...any) {
|
||||
l.config.Logger.Info(message, args...)
|
||||
}
|
||||
|
||||
func (l *LoggerService) Warning(message string, args ...any) {
|
||||
l.config.Logger.Warn(message, args...)
|
||||
}
|
||||
|
||||
func (l *LoggerService) Error(message string, args ...any) {
|
||||
l.config.Logger.Error(message, args...)
|
||||
}
|
||||
|
||||
func (l *LoggerService) SetLogLevel(level slog.Level) {
|
||||
l.level.Set(level)
|
||||
}
|
||||
127
v3/pkg/services/sqlite/sqlite.go
Normal file
127
v3/pkg/services/sqlite/sqlite.go
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
// ---------------- Service Setup ----------------
|
||||
// This is the main Service struct. It can be named anything you like.
|
||||
|
||||
type Config struct {
|
||||
DBFile string
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
config *Config
|
||||
conn *sql.DB
|
||||
}
|
||||
|
||||
func New(config *Config) *Service {
|
||||
return &Service{
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// OnShutdown is called when the app is shutting down
|
||||
// You can use this to clean up any resources you have allocated
|
||||
func (s *Service) OnShutdown() error {
|
||||
if s.conn != nil {
|
||||
return s.conn.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name returns the name of the plugin.
|
||||
// You should use the go module format e.g. github.com/myuser/myplugin
|
||||
func (s *Service) Name() string {
|
||||
return "github.com/wailsapp/wails/v3/plugins/sqlite"
|
||||
}
|
||||
|
||||
// OnStartup is called when the app is starting up. You can use this to
|
||||
// initialise any resources you need.
|
||||
func (s *Service) OnStartup(ctx context.Context, options application.ServiceOptions) error {
|
||||
if s.config.DBFile == "" {
|
||||
return errors.New(`no database file specified. Please set DBFile in the config to either a filename or use ":memory:" to use an in-memory database`)
|
||||
}
|
||||
db, err := s.Open(s.config.DBFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = db
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) Open(dbPath string) (string, error) {
|
||||
var err error
|
||||
s.conn, err = sql.Open("sqlite", dbPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "Database connection opened", nil
|
||||
}
|
||||
|
||||
func (s *Service) Execute(query string, args ...any) error {
|
||||
if s.conn == nil {
|
||||
return errors.New("no open database connection")
|
||||
}
|
||||
|
||||
_, err := s.conn.Exec(query, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) Select(query string, args ...any) ([]map[string]any, error) {
|
||||
if s.conn == nil {
|
||||
return nil, errors.New("no open database connection")
|
||||
}
|
||||
|
||||
rows, err := s.conn.Query(query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
columns, err := rows.Columns()
|
||||
var results []map[string]any
|
||||
for rows.Next() {
|
||||
values := make([]any, len(columns))
|
||||
pointers := make([]any, len(columns))
|
||||
|
||||
for i := range values {
|
||||
pointers[i] = &values[i]
|
||||
}
|
||||
|
||||
if err := rows.Scan(pointers...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
row := make(map[string]any, len(columns))
|
||||
for i, column := range columns {
|
||||
row[column] = values[i]
|
||||
}
|
||||
results = append(results, row)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (s *Service) Close() (string, error) {
|
||||
if s.conn == nil {
|
||||
return "", errors.New("no open database connection")
|
||||
}
|
||||
|
||||
err := s.conn.Close()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
s.conn = nil
|
||||
return "Database connection closed", nil
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
# KVStore Plugin
|
||||
|
||||
This plugin provides a simple key/value store for your Wails applications.
|
||||
|
||||
## Installation
|
||||
|
||||
Add the plugin to the `Plugins` option in the Applications options:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"github.com/wailsapp/wails/v3/plugins/kvstore"
|
||||
)
|
||||
|
||||
func main() {
|
||||
kvstorePlugin := kvstore.NewPlugin(&kvstore.Config{
|
||||
Filename: "myapp.db",
|
||||
})
|
||||
app := application.New(application.Options{
|
||||
// ...
|
||||
Plugins: map[string]application.Plugin{
|
||||
"kvstore": kvstorePlugin,
|
||||
},
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Filename string
|
||||
AutoSave bool
|
||||
}
|
||||
```
|
||||
|
||||
- `Filename` - The name of the file to store the key/value pairs in. This file will be created in the application's data directory.
|
||||
- `AutoSave` - If true, the store will be saved to disk after every change. If false, you will need to call `Save()` to persist the changes.
|
||||
|
||||
## Usage
|
||||
|
||||
### Go
|
||||
|
||||
You can call the methods exported by the plugin directly:
|
||||
|
||||
```go
|
||||
// Set a key
|
||||
err := kvstore.Set("url", "https://www.google.com")
|
||||
if err != nil {
|
||||
// handle error
|
||||
}
|
||||
// Get a key
|
||||
url := kvstore.Get("url").(string)
|
||||
|
||||
// Delete a key
|
||||
err = kvstore.Delete("url")
|
||||
if err != nil {
|
||||
// handle error
|
||||
}
|
||||
|
||||
// If you have not enables AutoSave, you will need to call Save() to persist the changes
|
||||
err = kvstore.Save()
|
||||
if err != nil {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
|
||||
You can call the methods from the frontend using the Plugin method:
|
||||
|
||||
```js
|
||||
wails.Plugin("kvstore","Set", "url", "https://www.google.com")
|
||||
wails.Plugin("kvstore","Get", "url").then((url) => {
|
||||
|
||||
})
|
||||
wails.Plugin("kvstore","Delete", "url").then((url) => {
|
||||
|
||||
})
|
||||
|
||||
// or
|
||||
wails.Plugin("browser","OpenFile","/path/to/file")
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
If you find a bug in this plugin, please raise a ticket on the Wails [Issue Tracker](https://github.com/wailsapp/wails/issues).
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
// plugin.js
|
||||
// This file should contain helper functions for the that can be used by the frontend.
|
||||
// Below are examples of how to use JSDoc to define the Hashes struct and the exported functions.
|
||||
|
||||
import { Call } from '/wails/runtime.js';
|
||||
|
||||
/**
|
||||
* Get the value of a key.
|
||||
* @param key {string} - The store key.
|
||||
* @returns {Promise<any>} - The value of the key.
|
||||
*/
|
||||
export function Get(key) {
|
||||
return Call.ByID(3322496224, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a key.
|
||||
@param key {string} - The store key.
|
||||
@param value {any} - The value to set.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export function Set(key, value) {
|
||||
return Call.ByID(1207638860, key, value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the database to disk.
|
||||
* @returns {Promise<void|Error>}
|
||||
*/
|
||||
export function Save() {
|
||||
return Call.ByID(1377075201);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a key from the store.
|
||||
* @param key {string} - The key to delete.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export function Delete(key) {
|
||||
return Call.ByID(737249231, key);
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
# This is the plugin definition file for the "kvstore" plugin.
|
||||
---
|
||||
Name: kvstore
|
||||
Description: A Simple Key/Value Store for Wails Applications
|
||||
Author: Lea Anthony
|
||||
Version: v1.0.0
|
||||
Website: https://wails.io
|
||||
Repository: https://github.com/wailsapp/wails/v3/plugins/kvstore
|
||||
License: MIT
|
||||
|
||||
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
# log Plugin
|
||||
|
||||
This example plugin provides a way to generate hashes of strings.
|
||||
|
||||
## Installation
|
||||
|
||||
Add the plugin to the `Plugins` option in the Applications options:
|
||||
|
||||
```go
|
||||
Plugins: map[string]application.Plugin{
|
||||
"log": log.NewPlugin(),
|
||||
},
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
You can then call the methods from the frontend:
|
||||
|
||||
```js
|
||||
wails.Plugin("log","Debug","hello world")
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
- Trace
|
||||
- Debug
|
||||
- Info
|
||||
- Warning
|
||||
- Error
|
||||
- Fatal
|
||||
- SetLevel
|
||||
|
||||
SetLevel takes an integer value from JS:
|
||||
|
||||
```js
|
||||
wails.Plugin("log","SetLevel",1)
|
||||
```
|
||||
|
||||
Levels are:
|
||||
|
||||
- Trace: 1
|
||||
- Debug: 2
|
||||
- Info: 3
|
||||
- Warning: 4
|
||||
- Error: 5
|
||||
- Fatal: 6
|
||||
|
||||
## Support
|
||||
|
||||
If you find a bug in this plugin, please raise a ticket [here](https://github.com/plugin/repository).
|
||||
Please do not contact the Wails team for support.
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
// plugin.js
|
||||
// This file should contain helper functions for the that can be used by the frontend.
|
||||
// Below are examples of how to use JSDoc to define the Hashes struct and the exported functions.
|
||||
|
||||
import {Call} from '/wails/runtime.js';
|
||||
|
||||
/**
|
||||
* Log at the Debug level.
|
||||
* @param input {string} - The message in printf format.
|
||||
* @param args {...any} - The arguments for the log message.
|
||||
* @returns {Promise<void|Error>}
|
||||
*/
|
||||
|
||||
export function Debug(input, ...args) {
|
||||
return Call.ByID(4111675027, input, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log at the Info level.
|
||||
* @param input {string} - The message in printf format.
|
||||
* @param args {...any} - The arguments for the log message.
|
||||
* @returns {Promise<void|Error>}
|
||||
*/
|
||||
export function Info(input, ...args) {
|
||||
return Call.ByID(2391172776, input, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log at the Warning level.
|
||||
* @param input {string} - The message in printf format.
|
||||
* @param args {...any} - The arguments for the log message.
|
||||
* @returns {Promise<void|Error>}
|
||||
*/
|
||||
export function Warning(input, ...args) {
|
||||
return Call.ByID(2762394760, input, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log at the Error level.
|
||||
* @param input {string} - The message in printf format.
|
||||
* @param args {...any} - The arguments for the log message.
|
||||
* @returns {Promise<void|Error>}
|
||||
*/
|
||||
export function Error(input, ...args) {
|
||||
return Call.ByID(878590242, input, ...args);
|
||||
}
|
||||
|
||||
export const LevelDebug = -4
|
||||
export const LevelInfo = 0
|
||||
export const LevelWarn = 4
|
||||
export const LevelError = 8
|
||||
|
||||
|
||||
/**
|
||||
* Set Log level
|
||||
* @param level {LogLevel} - The log level to set.
|
||||
* @returns {Promise<void|Error>}
|
||||
*/
|
||||
export function SetLogLevel(level) {
|
||||
return Call.ByID(2758810652, level);
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
//go:embed assets/*
|
||||
var assets embed.FS
|
||||
|
||||
// ---------------- Plugin Setup ----------------
|
||||
// This is the main plugin struct. It can be named anything you like.
|
||||
// It must implement the application.Plugin interface.
|
||||
// Both the Init() and Shutdown() methods are called synchronously when the app starts and stops.
|
||||
|
||||
type Config struct {
|
||||
// Logger is the logger to use. If not set, a default logger will be used.
|
||||
Logger *slog.Logger
|
||||
|
||||
// LogLevel defines the log level of the logger.
|
||||
LogLevel slog.Level
|
||||
|
||||
// Handles errors that occur when writing to the log
|
||||
ErrorHandler func(err error)
|
||||
}
|
||||
|
||||
type Plugin struct {
|
||||
config *Config
|
||||
app *application.App
|
||||
level slog.LevelVar
|
||||
}
|
||||
|
||||
func NewPluginWithConfig(config *Config) *Plugin {
|
||||
if config.Logger == nil {
|
||||
config.Logger = application.DefaultLogger(config.LogLevel)
|
||||
}
|
||||
|
||||
result := &Plugin{
|
||||
config: config,
|
||||
}
|
||||
result.level.Set(config.LogLevel)
|
||||
return result
|
||||
}
|
||||
|
||||
func NewPlugin() *Plugin {
|
||||
return NewPluginWithConfig(&Config{})
|
||||
}
|
||||
|
||||
// Shutdown is called when the app is shutting down
|
||||
// You can use this to clean up any resources you have allocated
|
||||
func (p *Plugin) Shutdown() error { return nil }
|
||||
|
||||
// Name returns the name of the plugin.
|
||||
// You should use the go module format e.g. github.com/myuser/myplugin
|
||||
func (p *Plugin) Name() string {
|
||||
return "github.com/wailsapp/wails/v3/plugins/log"
|
||||
}
|
||||
|
||||
func (p *Plugin) Init(api application.PluginAPI) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CallableByJS returns a list of methods that can be called from the frontend
|
||||
func (p *Plugin) CallableByJS() []string {
|
||||
return []string{
|
||||
"Debug",
|
||||
"Info",
|
||||
"Warning",
|
||||
"Error",
|
||||
"SetLogLevel",
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) Assets() fs.FS {
|
||||
return assets
|
||||
}
|
||||
|
||||
// ---------------- Plugin Methods ----------------
|
||||
// Plugin methods are just normal Go methods. You can add as many as you like.
|
||||
// The only requirement is that they are exported (start with a capital letter).
|
||||
// You can also return any type that is JSON serializable.
|
||||
// See https://golang.org/pkg/encoding/json/#Marshal for more information.
|
||||
|
||||
func (p *Plugin) Debug(message string, args ...any) {
|
||||
p.config.Logger.Debug(message, args...)
|
||||
}
|
||||
|
||||
func (p *Plugin) Info(message string, args ...any) {
|
||||
p.config.Logger.Info(message, args...)
|
||||
}
|
||||
|
||||
func (p *Plugin) Warning(message string, args ...any) {
|
||||
p.config.Logger.Warn(message, args...)
|
||||
}
|
||||
|
||||
func (p *Plugin) Error(message string, args ...any) {
|
||||
p.config.Logger.Error(message, args...)
|
||||
}
|
||||
|
||||
func (p *Plugin) SetLogLevel(level slog.Level) {
|
||||
p.level.Set(level)
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
# This is the plugin definition file for the "log" plugin.
|
||||
---
|
||||
Name: log
|
||||
Description: A basic logger
|
||||
Author: Lea Anthony
|
||||
Version: v1.0.0
|
||||
Website: https://wails.io
|
||||
Repository: https://github.com/wailsapp/wails/v3/plugins/log
|
||||
License: MIT
|
||||
|
||||
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
|
||||
import {Call} from '/wails/runtime.js';
|
||||
|
||||
/**
|
||||
* Open a sqlite DB.
|
||||
* @param filename {string} - file to open.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export function Open(filename) {
|
||||
return Call.ByID(147348976, filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a sqlite DB.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export function Close() {
|
||||
return Call.ByID(3998329564);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a SQL statement.
|
||||
* @param statement {string} - SQL statement to execute.
|
||||
* @param args {...any} - Arguments to pass to the statement.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export function Execute(statement, ...args) {
|
||||
return Call.ByID(2804887383, statement, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a select query.
|
||||
* @param statement {string} - Select SQL statement.
|
||||
* @param args {...any} - Arguments to pass to the statement.
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export function Select(statement, ...args) {
|
||||
return Call.ByID(2209315040, statement, ...args);
|
||||
}
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"embed"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"io/fs"
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
//go:embed assets/*
|
||||
var assets embed.FS
|
||||
|
||||
// ---------------- Plugin Setup ----------------
|
||||
// This is the main plugin struct. It can be named anything you like.
|
||||
// It must implement the application.Plugin interface.
|
||||
// Both the Init() and Shutdown() methods are called synchronously when the app starts and stops.
|
||||
|
||||
type Config struct {
|
||||
DBFile string
|
||||
CanCallOpen bool
|
||||
CanCallClose bool
|
||||
}
|
||||
|
||||
type Plugin struct {
|
||||
config *Config
|
||||
conn *sql.DB
|
||||
callableMethods []string
|
||||
js string
|
||||
}
|
||||
|
||||
func NewPlugin(config *Config) *Plugin {
|
||||
return &Plugin{
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown is called when the app is shutting down
|
||||
// You can use this to clean up any resources you have allocated
|
||||
func (p *Plugin) Shutdown() error {
|
||||
if p.conn != nil {
|
||||
return p.conn.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name returns the name of the plugin.
|
||||
// You should use the go module format e.g. github.com/myuser/myplugin
|
||||
func (p *Plugin) Name() string {
|
||||
return "github.com/wailsapp/wails/v3/plugins/sqlite"
|
||||
}
|
||||
|
||||
// Init is called when the app is starting up. You can use this to
|
||||
// initialise any resources you need.
|
||||
func (p *Plugin) Init(api application.PluginAPI) error {
|
||||
p.callableMethods = []string{"Execute", "Select"}
|
||||
if p.config.CanCallOpen {
|
||||
p.callableMethods = append(p.callableMethods, "Open")
|
||||
}
|
||||
if p.config.CanCallClose {
|
||||
p.callableMethods = append(p.callableMethods, "Close")
|
||||
}
|
||||
if p.config.DBFile == "" {
|
||||
return errors.New(`no database file specified. Please set DBFile in the config to either a filename or use ":memory:" to use an in-memory database`)
|
||||
}
|
||||
_, err := p.Open(p.config.DBFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CallableByJS returns a list of exported methods that can be called from the frontend
|
||||
func (p *Plugin) CallableByJS() []string {
|
||||
return p.callableMethods
|
||||
}
|
||||
|
||||
func (p *Plugin) Assets() fs.FS {
|
||||
return assets
|
||||
}
|
||||
|
||||
// ---------------- Plugin Methods ----------------
|
||||
// Plugin methods are just normal Go methods. You can add as many as you like.
|
||||
// The only requirement is that they are exported (start with a capital letter).
|
||||
// You can also return any type that is JSON serializable.
|
||||
// Any methods that you want to be callable from the frontend must be returned by the
|
||||
// Exported() method above.
|
||||
// See https://golang.org/pkg/encoding/json/#Marshal for more information.
|
||||
|
||||
func (p *Plugin) Open(dbPath string) (string, error) {
|
||||
var err error
|
||||
p.conn, err = sql.Open("sqlite", dbPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "Database connection opened", nil
|
||||
}
|
||||
|
||||
func (p *Plugin) Execute(query string, args ...any) error {
|
||||
if p.conn == nil {
|
||||
return errors.New("no open database connection")
|
||||
}
|
||||
|
||||
_, err := p.conn.Exec(query, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Plugin) Select(query string, args ...any) ([]map[string]any, error) {
|
||||
if p.conn == nil {
|
||||
return nil, errors.New("no open database connection")
|
||||
}
|
||||
|
||||
rows, err := p.conn.Query(query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
columns, err := rows.Columns()
|
||||
var results []map[string]any
|
||||
for rows.Next() {
|
||||
values := make([]any, len(columns))
|
||||
pointers := make([]any, len(columns))
|
||||
|
||||
for i := range values {
|
||||
pointers[i] = &values[i]
|
||||
}
|
||||
|
||||
if err := rows.Scan(pointers...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
row := make(map[string]any, len(columns))
|
||||
for i, column := range columns {
|
||||
row[column] = values[i]
|
||||
}
|
||||
results = append(results, row)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (p *Plugin) Close() (string, error) {
|
||||
if p.conn == nil {
|
||||
return "", errors.New("no open database connection")
|
||||
}
|
||||
|
||||
err := p.conn.Close()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
p.conn = nil
|
||||
return "Database connection closed", nil
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
# This is the plugin definition file for the "sqlite" plugin.
|
||||
---
|
||||
Name: sqlite
|
||||
Description: Provides easy access to SQLite DBs
|
||||
Author: Lea Anthony
|
||||
Version: v1.0.0
|
||||
Website: https://wails.io/plugins/sqlite
|
||||
Repository: https://github.com/wailsapp/wails/v3/plugins/sqlite
|
||||
License: MIT
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue