mirror of
https://github.com/taigrr/wails.git
synced 2026-04-15 03:11:14 -07:00
Compare commits
120 Commits
bh90210-11
...
update-wai
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fbfccdd86 | ||
|
|
1d1a7967ad | ||
|
|
0b6f256d55 | ||
|
|
694f80434a | ||
|
|
0a57fa4035 | ||
|
|
099967ae94 | ||
|
|
718bb1b852 | ||
|
|
af1a1a2498 | ||
|
|
cc0617d247 | ||
|
|
99a3f87cef | ||
|
|
1ccdb1bc4e | ||
|
|
62b1967e45 | ||
|
|
c10303e7c0 | ||
|
|
4a61584827 | ||
|
|
cf249ba836 | ||
|
|
08fe7b64d6 | ||
|
|
77939ea414 | ||
|
|
468394d03c | ||
|
|
dc87699a1e | ||
|
|
36e906507d | ||
|
|
a5f9688708 | ||
|
|
880f900e51 | ||
|
|
349306cf73 | ||
|
|
f140697857 | ||
|
|
3d9e9a1342 | ||
|
|
1a82406d2b | ||
|
|
26ff8df7e5 | ||
|
|
54b4b157b3 | ||
|
|
add7e89097 | ||
|
|
b7dae216df | ||
|
|
0b9d093d6c | ||
|
|
7f282ad071 | ||
|
|
d6ed583e07 | ||
|
|
930cab2d9d | ||
|
|
ae41f33dcc | ||
|
|
5af6b7cafe | ||
|
|
68ac3763d0 | ||
|
|
cdc66b556e | ||
|
|
3ff16322c2 | ||
|
|
d60066a0b1 | ||
|
|
9d6ebf0fd4 | ||
|
|
839815e2fb | ||
|
|
846fe479bf | ||
|
|
62f7070e0c | ||
|
|
dd418b36c2 | ||
|
|
f4f04f2199 | ||
|
|
3a7514bbdc | ||
|
|
213f07fed4 | ||
|
|
ed3ed8aa18 | ||
|
|
d038dca37c | ||
|
|
bb86d770a1 | ||
|
|
33daa8621e | ||
|
|
6c124fcff4 | ||
|
|
45833574b3 | ||
|
|
5cb00eb481 | ||
|
|
e2105331c1 | ||
|
|
21d2383e63 | ||
|
|
6c945a4eed | ||
|
|
6c8d34dfd3 | ||
|
|
b9b42c059e | ||
|
|
3f657b34cf | ||
|
|
6e81a36ada | ||
|
|
ddec01a429 | ||
|
|
21fdb3be7d | ||
|
|
c1a13ab6d0 | ||
|
|
750a02efc6 | ||
|
|
5e047debfc | ||
|
|
9cac336708 | ||
|
|
827c2b9a95 | ||
|
|
b36a3c4abb | ||
|
|
0bac205565 | ||
|
|
67a8ad8e12 | ||
|
|
9de2f66f50 | ||
|
|
9370030ff3 | ||
|
|
e38d6e7ef0 | ||
|
|
2f21fc3575 | ||
|
|
63e73f5f64 | ||
|
|
e1adc1ba49 | ||
|
|
030e911ea4 | ||
|
|
d2f114e44e | ||
|
|
700d3f84d3 | ||
|
|
1d49042013 | ||
|
|
8671b1e6cf | ||
|
|
517d6c44ec | ||
|
|
a082a659ea | ||
|
|
083153efc9 | ||
|
|
65a2560153 | ||
|
|
29535c10a3 | ||
|
|
24c7362163 | ||
|
|
f6ff7d7b16 | ||
|
|
b0a075cdf2 | ||
|
|
98d4d6b33c | ||
|
|
9ba3e0512b | ||
|
|
eff63175e5 | ||
|
|
75a0b632bc | ||
|
|
a2af626477 | ||
|
|
8aa97f64ef | ||
|
|
caa1e04b5a | ||
|
|
cddf6a0204 | ||
|
|
9fa1f42dc7 | ||
|
|
c7e709d487 | ||
|
|
6801398f3d | ||
|
|
982d14c049 | ||
|
|
ddbaf55ae7 | ||
|
|
5552a8501b | ||
|
|
b997becb2f | ||
|
|
753516bab7 | ||
|
|
89992d8636 | ||
|
|
7dd42f964b | ||
|
|
078a7a5519 | ||
|
|
d811f721ac | ||
|
|
26950ba045 | ||
|
|
80adb70e78 | ||
|
|
0c042acd4a | ||
|
|
0ad0c4151a | ||
|
|
65a8a1e1f7 | ||
|
|
a2ac8af882 | ||
|
|
52afbd3f15 | ||
|
|
ce35ee5ca8 | ||
|
|
63f1767755 |
@@ -1,42 +0,0 @@
|
|||||||
{{ if .Versions -}}
|
|
||||||
<a name="unreleased"></a>
|
|
||||||
## [Unreleased]
|
|
||||||
|
|
||||||
{{ if .Unreleased.CommitGroups -}}
|
|
||||||
{{ range .Unreleased.CommitGroups -}}
|
|
||||||
### {{ .Title }}
|
|
||||||
{{ range .Commits -}}
|
|
||||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{ range .Versions }}
|
|
||||||
<a name="{{ .Tag.Name }}"></a>
|
|
||||||
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
|
|
||||||
{{ range .CommitGroups -}}
|
|
||||||
### {{ .Title }}
|
|
||||||
{{ range .Commits -}}
|
|
||||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{- if .NoteGroups -}}
|
|
||||||
{{ range .NoteGroups -}}
|
|
||||||
### {{ .Title }}
|
|
||||||
{{ range .Notes }}
|
|
||||||
{{ .Body }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
|
|
||||||
{{- if .Versions }}
|
|
||||||
[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD
|
|
||||||
{{ range .Versions -}}
|
|
||||||
{{ if .Tag.Previous -}}
|
|
||||||
[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
style: github
|
|
||||||
template: CHANGELOG.tpl.md
|
|
||||||
info:
|
|
||||||
title: CHANGELOG
|
|
||||||
repository_url: https://github.com/wailsapp/wails
|
|
||||||
options:
|
|
||||||
commits:
|
|
||||||
# filters:
|
|
||||||
# Type:
|
|
||||||
# - feat
|
|
||||||
# - fix
|
|
||||||
# - perf
|
|
||||||
# - refactor
|
|
||||||
commit_groups:
|
|
||||||
# title_maps:
|
|
||||||
# feat: Features
|
|
||||||
# fix: Bug Fixes
|
|
||||||
# perf: Performance Improvements
|
|
||||||
# refactor: Code Refactoring
|
|
||||||
header:
|
|
||||||
pattern: "^(\\w*)\\:\\s(.*)$"
|
|
||||||
pattern_maps:
|
|
||||||
- Type
|
|
||||||
- Subject
|
|
||||||
notes:
|
|
||||||
keywords:
|
|
||||||
- BREAKING CHANGE
|
|
||||||
1
.eslintignore
Normal file
1
.eslintignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
runtime/assets/default.html
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
module.exports = {
|
{
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"es6": true
|
"es6": true,
|
||||||
|
"node": true,
|
||||||
},
|
},
|
||||||
"extends": "eslint:recommended",
|
"extends": "eslint:recommended",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
@@ -26,4 +27,4 @@ module.exports = {
|
|||||||
"always"
|
"always"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
19
.github/stale.yml
vendored
Normal file
19
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Number of days of inactivity before an issue becomes stale
|
||||||
|
daysUntilStale: 30
|
||||||
|
# Number of days of inactivity before a stale issue is closed
|
||||||
|
daysUntilClose: 7
|
||||||
|
# Issues with these labels will never be considered stale
|
||||||
|
exemptLabels:
|
||||||
|
- pinned
|
||||||
|
- security
|
||||||
|
- onhold
|
||||||
|
- inprogress
|
||||||
|
# Label to use when marking an issue as stale
|
||||||
|
staleLabel: wontfix
|
||||||
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
|
markComment: >
|
||||||
|
This issue has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
|
for your contributions.
|
||||||
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||||
|
closeComment: false
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -16,4 +16,4 @@ examples/**/example*
|
|||||||
cmd/wails/wails
|
cmd/wails/wails
|
||||||
.DS_Store
|
.DS_Store
|
||||||
tmp
|
tmp
|
||||||
dist
|
node_modules/
|
||||||
6
.hound.yml
Normal file
6
.hound.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
jshint:
|
||||||
|
config_file: .jshintrc
|
||||||
|
eslint:
|
||||||
|
enabled: true
|
||||||
|
config_file: .eslintrc
|
||||||
|
ignore_file: .eslintignore
|
||||||
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -4,6 +4,13 @@
|
|||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Test cmd package",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "test",
|
||||||
|
"program": "${workspaceFolder}/cmd/"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Wails Init",
|
"name": "Wails Init",
|
||||||
"type": "go",
|
"type": "go",
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
|
||||||
|
2019-07-20 **v0.17.6-pre**
|
||||||
|
* Significant refactor of runtime
|
||||||
|
* Removed wailsbridge file - now a unified approach taken
|
||||||
|
* Fixed React on Windows - Thanks [Florian Didran](https://github.com/fdidron)!
|
||||||
|
|
||||||
2019-06-18 **v0.16.0**
|
2019-06-18 **v0.16.0**
|
||||||
* React template FTW! - Thanks [admin_3.exe](https://github.com/bh90210)!
|
* React template FTW! - Thanks [admin_3.exe](https://github.com/bh90210)!
|
||||||
* Updated contributors
|
* Updated contributors
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ Wails is what it is because of the time and effort given by these great people.
|
|||||||
* [Qais Patankar](https://github.com/qaisjp)
|
* [Qais Patankar](https://github.com/qaisjp)
|
||||||
* [Anthony Lee](https://github.com/alee792)
|
* [Anthony Lee](https://github.com/alee792)
|
||||||
* [Adrian Lanzafame](https://github.com/lanzafame)
|
* [Adrian Lanzafame](https://github.com/lanzafame)
|
||||||
|
* [Mattn](https://github.com/mattn)
|
||||||
* [0xflotus](https://github.com/0xflotus)
|
* [0xflotus](https://github.com/0xflotus)
|
||||||
* [Michael D Henderson](https://github.com/mdhender)
|
* [Michael D Henderson](https://github.com/mdhender)
|
||||||
* [fred2104](https://github.com/fishfishfish2104)
|
* [fred2104](https://github.com/fishfishfish2104)
|
||||||
@@ -13,3 +14,7 @@ Wails is what it is because of the time and effort given by these great people.
|
|||||||
* [Mark Stenglein](https://github.com/ocelotsloth)
|
* [Mark Stenglein](https://github.com/ocelotsloth)
|
||||||
* [admin_3.exe](https://github.com/bh90210)
|
* [admin_3.exe](https://github.com/bh90210)
|
||||||
* [iceleo-com](https://github.com/iceleo-com)
|
* [iceleo-com](https://github.com/iceleo-com)
|
||||||
|
* [fallendusk](https://github.com/fallendusk)
|
||||||
|
* [Florian Didran](https://github.com/fdidron)
|
||||||
|
* [Nikolai Zimmermann](https://github.com/Chronophylos)
|
||||||
|
* [Toyam Cox](https://github.com/Vaelatern)
|
||||||
|
|||||||
37
README.md
37
README.md
@@ -8,9 +8,10 @@
|
|||||||
<a href="http://godoc.org/github.com/wailsapp/wails"><img src="https://img.shields.io/badge/godoc-reference-blue.svg"/></a>
|
<a href="http://godoc.org/github.com/wailsapp/wails"><img src="https://img.shields.io/badge/godoc-reference-blue.svg"/></a>
|
||||||
<a href="https://www.codefactor.io/repository/github/wailsapp/wails"><img src="https://www.codefactor.io/repository/github/wailsapp/wails/badge" alt="CodeFactor" /></a>
|
<a href="https://www.codefactor.io/repository/github/wailsapp/wails"><img src="https://www.codefactor.io/repository/github/wailsapp/wails/badge" alt="CodeFactor" /></a>
|
||||||
<a href="https://github.com/wailsapp/wails/issues"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat" alt="CodeFactor" /></a>
|
<a href="https://github.com/wailsapp/wails/issues"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat" alt="CodeFactor" /></a>
|
||||||
|
<a href="https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_shield" alt="FOSSA Status"><img src="https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=shield"/></a>
|
||||||
<a href="https://houndci.com"><img src="https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg"/></a>
|
<a href="https://houndci.com"><img src="https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg"/></a>
|
||||||
<a href="https://github.com/avelino/awesome-go" rel="nofollow"><img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome"></a>
|
<a href="https://github.com/avelino/awesome-go" rel="nofollow"><img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome"></a>
|
||||||
<a href="https://dashboard.guardrails.io/default/gh/wailsapp/wails"><img src="https://badges.guardrails.io/wailsapp/wails.svg?token=53657bc22ec360d7673c894fdd70568e918ec581d10d84427ed4de5fe1eeff1a"></a>
|
<a href="https://dev.azure.com/leaanthony/Wails/_build/latest?definitionId=1&branchName=master" rel="nofollow"><img src="https://dev.azure.com/leaanthony/Wails/_apis/build/status/wailsapp.wails?branchName=master" alt="Pipelines"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative!
|
The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative!
|
||||||
@@ -46,19 +47,40 @@ Make sure you have the xcode command line tools installed. This can be done by r
|
|||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
#### Ubuntu 18.04, Debian 9
|
#### Debian/Ubuntu
|
||||||
|
|
||||||
`sudo apt install pkg-config build-essential libgtk-3-dev libwebkit2gtk-4.0-dev`
|
`sudo apt install libgtk-3-dev libwebkit2gtk-4.0-dev`
|
||||||
|
|
||||||
|
_Debian: 8, 9, 10_
|
||||||
|
_Ubuntu: 16.04, 18.04, 19.04_
|
||||||
|
|
||||||
|
_Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali-Rolling_
|
||||||
|
|
||||||
#### Arch Linux
|
#### Arch Linux
|
||||||
|
|
||||||
`sudo pacman -S webkit2gtk gtk3`
|
`sudo pacman -S webkit2gtk gtk3`
|
||||||
|
|
||||||
#### Red Hat Based Distros
|
_Also succesfully test on: ArcoLinuxB_
|
||||||
|
|
||||||
`sudo yum install webkit2gtk-devel gtk3-devel`
|
#### Centos
|
||||||
|
|
||||||
Note: If you have successfully installed these dependencies on a different flavour of Linux, please consider submitting a PR.
|
`sudo yum install webkitgtk3-devel gtk3-devel`
|
||||||
|
|
||||||
|
_CentOS 6, 7_
|
||||||
|
|
||||||
|
#### Fedora
|
||||||
|
|
||||||
|
`sudo yum install webkit2gtk3-devel gtk3-devel`
|
||||||
|
|
||||||
|
_Fedora 29, 30_
|
||||||
|
|
||||||
|
#### VoidLinux & VoidLinux-musl
|
||||||
|
|
||||||
|
`xbps-install gtk+3-devel webkit2gtk-devel`
|
||||||
|
|
||||||
|
#### Gentoo
|
||||||
|
|
||||||
|
`sudo emerge gtk+:3 webkit-gtk`
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
@@ -122,3 +144,6 @@ This project was mainly coded to the following albums:
|
|||||||
* [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF)
|
* [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF)
|
||||||
* [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v)
|
* [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v)
|
||||||
|
|
||||||
|
## Licensing
|
||||||
|
|
||||||
|
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large)
|
||||||
|
|||||||
46
app.go
46
app.go
@@ -2,6 +2,12 @@ package wails
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/cmd"
|
"github.com/wailsapp/wails/cmd"
|
||||||
|
"github.com/wailsapp/wails/lib/binding"
|
||||||
|
"github.com/wailsapp/wails/lib/event"
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/ipc"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/lib/renderer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------------------------------- Compile time Flags ------------------------------
|
// -------------------------------- Compile time Flags ------------------------------
|
||||||
@@ -15,13 +21,13 @@ var BuildMode = cmd.BuildModeProd
|
|||||||
type App struct {
|
type App struct {
|
||||||
config *AppConfig // The Application configuration object
|
config *AppConfig // The Application configuration object
|
||||||
cli *cmd.Cli // In debug mode, we have a cli
|
cli *cmd.Cli // In debug mode, we have a cli
|
||||||
renderer Renderer // The renderer is what we will render the app to
|
renderer interfaces.Renderer // The renderer is what we will render the app to
|
||||||
logLevel string // The log level of the app
|
logLevel string // The log level of the app
|
||||||
ipc *ipcManager // Handles the IPC calls
|
ipc interfaces.IPCManager // Handles the IPC calls
|
||||||
log *CustomLogger // Logger
|
log *logger.CustomLogger // Logger
|
||||||
bindingManager *bindingManager // Handles binding of Go code to renderer
|
bindingManager interfaces.BindingManager // Handles binding of Go code to renderer
|
||||||
eventManager *eventManager // Handles all the events
|
eventManager interfaces.EventManager // Handles all the events
|
||||||
runtime *Runtime // The runtime object for registered structs
|
runtime interfaces.Runtime // The runtime object for registered structs
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateApp creates the application window with the given configuration
|
// CreateApp creates the application window with the given configuration
|
||||||
@@ -34,14 +40,14 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
|
|||||||
|
|
||||||
result := &App{
|
result := &App{
|
||||||
logLevel: "info",
|
logLevel: "info",
|
||||||
renderer: &webViewRenderer{},
|
renderer: renderer.NewWebView(),
|
||||||
ipc: newIPCManager(),
|
ipc: ipc.NewManager(),
|
||||||
bindingManager: newBindingManager(),
|
bindingManager: binding.NewManager(),
|
||||||
eventManager: newEventManager(),
|
eventManager: event.NewManager(),
|
||||||
log: newCustomLogger("App"),
|
log: logger.NewCustomLogger("App"),
|
||||||
}
|
}
|
||||||
|
|
||||||
appconfig, err := newAppConfig(userConfig)
|
appconfig, err := newConfig(userConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.log.Fatalf("Cannot use custom HTML: %s", err.Error())
|
result.log.Fatalf("Cannot use custom HTML: %s", err.Error())
|
||||||
}
|
}
|
||||||
@@ -75,14 +81,14 @@ func (a *App) Run() error {
|
|||||||
func (a *App) start() error {
|
func (a *App) start() error {
|
||||||
|
|
||||||
// Set the log level
|
// Set the log level
|
||||||
setLogLevel(a.logLevel)
|
logger.SetLogLevel(a.logLevel)
|
||||||
|
|
||||||
// Log starup
|
// Log starup
|
||||||
a.log.Info("Starting")
|
a.log.Info("Starting")
|
||||||
|
|
||||||
// Check if we are to run in headless mode
|
// Check if we are to run in bridge mode
|
||||||
if BuildMode == cmd.BuildModeBridge {
|
if BuildMode == cmd.BuildModeBridge {
|
||||||
a.renderer = &Headless{}
|
a.renderer = &renderer.Bridge{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise the renderer
|
// Initialise the renderer
|
||||||
@@ -92,16 +98,16 @@ func (a *App) start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start event manager and give it our renderer
|
// Start event manager and give it our renderer
|
||||||
a.eventManager.start(a.renderer)
|
a.eventManager.Start(a.renderer)
|
||||||
|
|
||||||
// Start the IPC Manager and give it the event manager and binding manager
|
// Start the IPC Manager and give it the event manager and binding manager
|
||||||
a.ipc.start(a.eventManager, a.bindingManager)
|
a.ipc.Start(a.eventManager, a.bindingManager)
|
||||||
|
|
||||||
// Create the runtime
|
// Create the runtime
|
||||||
a.runtime = newRuntime(a.eventManager, a.renderer)
|
a.runtime = NewRuntime(a.eventManager, a.renderer)
|
||||||
|
|
||||||
// Start binding manager and give it our renderer
|
// Start binding manager and give it our renderer
|
||||||
err = a.bindingManager.start(a.renderer, a.runtime)
|
err = a.bindingManager.Start(a.renderer, a.runtime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -113,5 +119,5 @@ func (a *App) start() error {
|
|||||||
// Bind allows the user to bind the given object
|
// Bind allows the user to bind the given object
|
||||||
// with the application
|
// with the application
|
||||||
func (a *App) Bind(object interface{}) {
|
func (a *App) Bind(object interface{}) {
|
||||||
a.bindingManager.bind(object)
|
a.bindingManager.Bind(object)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
package wails
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/dchest/htmlmin"
|
|
||||||
"github.com/leaanthony/mewn"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AppConfig is the configuration structure used when creating a Wails App object
|
|
||||||
type AppConfig struct {
|
|
||||||
Width, Height int
|
|
||||||
Title string
|
|
||||||
defaultHTML string
|
|
||||||
HTML string
|
|
||||||
JS string
|
|
||||||
CSS string
|
|
||||||
Colour string
|
|
||||||
Resizable bool
|
|
||||||
DisableInspector bool
|
|
||||||
isHTMLFragment bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AppConfig) merge(in *AppConfig) error {
|
|
||||||
if in.CSS != "" {
|
|
||||||
a.CSS = in.CSS
|
|
||||||
}
|
|
||||||
if in.Title != "" {
|
|
||||||
a.Title = in.Title
|
|
||||||
}
|
|
||||||
if in.HTML != "" {
|
|
||||||
minified, err := htmlmin.Minify([]byte(in.HTML), &htmlmin.Options{
|
|
||||||
MinifyScripts: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
inlineHTML := string(minified)
|
|
||||||
inlineHTML = strings.Replace(inlineHTML, "'", "\\'", -1)
|
|
||||||
inlineHTML = strings.Replace(inlineHTML, "\n", " ", -1)
|
|
||||||
a.HTML = strings.TrimSpace(inlineHTML)
|
|
||||||
|
|
||||||
// Deduce whether this is a full html page or a fragment
|
|
||||||
// The document is determined to be a fragment if an HTML
|
|
||||||
// tag exists and is located before the first div tag
|
|
||||||
HTMLTagIndex := strings.Index(a.HTML, "<html")
|
|
||||||
DivTagIndex := strings.Index(a.HTML, "<div")
|
|
||||||
|
|
||||||
if HTMLTagIndex == -1 {
|
|
||||||
a.isHTMLFragment = true
|
|
||||||
} else {
|
|
||||||
if DivTagIndex < HTMLTagIndex {
|
|
||||||
a.isHTMLFragment = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if in.Colour != "" {
|
|
||||||
a.Colour = in.Colour
|
|
||||||
}
|
|
||||||
|
|
||||||
if in.JS != "" {
|
|
||||||
a.JS = in.JS
|
|
||||||
}
|
|
||||||
|
|
||||||
if in.Width != 0 {
|
|
||||||
a.Width = in.Width
|
|
||||||
}
|
|
||||||
if in.Height != 0 {
|
|
||||||
a.Height = in.Height
|
|
||||||
}
|
|
||||||
a.Resizable = in.Resizable
|
|
||||||
a.DisableInspector = in.DisableInspector
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates the default configuration
|
|
||||||
func newAppConfig(userConfig *AppConfig) (*AppConfig, error) {
|
|
||||||
result := &AppConfig{
|
|
||||||
Width: 800,
|
|
||||||
Height: 600,
|
|
||||||
Resizable: true,
|
|
||||||
Title: "My Wails App",
|
|
||||||
Colour: "#FFF", // White by default
|
|
||||||
HTML: mewn.String("./wailsruntimeassets/default/default.html"),
|
|
||||||
}
|
|
||||||
|
|
||||||
if userConfig != nil {
|
|
||||||
err := result.merge(userConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
138
azure-pipelines.yaml
Normal file
138
azure-pipelines.yaml
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
# avoid double trigger by applying some rules
|
||||||
|
# start a pipeline when push to 'master' branch
|
||||||
|
trigger:
|
||||||
|
- master
|
||||||
|
# or when pull request on 'develop' branch
|
||||||
|
pr:
|
||||||
|
- develop
|
||||||
|
|
||||||
|
# for now there is only one stage 'Build'
|
||||||
|
# in the future we could use multistage strategy for releases
|
||||||
|
stages:
|
||||||
|
- stage: Build
|
||||||
|
|
||||||
|
# there are 3 jobs
|
||||||
|
# one for each os
|
||||||
|
jobs:
|
||||||
|
- deployment: Linux
|
||||||
|
displayName: Lin
|
||||||
|
variables:
|
||||||
|
GOPATH: '$(Agent.BuildDirectory)/gopath' # Go workspace path
|
||||||
|
GOROOT: '$(Agent.BuildDirectory)/go' # Go installation path
|
||||||
|
GOBIN: '$(GOPATH)/bin' # Go binaries path
|
||||||
|
GOMODULE: 'on'
|
||||||
|
modulePath: '$(Agent.BuildDirectory)/wails' # Path to the module's code
|
||||||
|
pool:
|
||||||
|
vmImage: 'Ubuntu-16.04'
|
||||||
|
environment: 'linux-dev'
|
||||||
|
strategy:
|
||||||
|
runOnce:
|
||||||
|
deploy:
|
||||||
|
steps:
|
||||||
|
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
|
||||||
|
clean: true # whether to fetch clean each time
|
||||||
|
path: wails # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
|
||||||
|
# go version 1.12.7
|
||||||
|
- script: |
|
||||||
|
wget "https://storage.googleapis.com/golang/go1.12.7.linux-amd64.tar.gz" --output-document "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
||||||
|
tar -C '$(Agent.BuildDirectory)' -xzf "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
||||||
|
displayName: 'Install Go 1.12.7 Linux'
|
||||||
|
- script: |
|
||||||
|
mkdir -p '$(GOBIN)'
|
||||||
|
mkdir -p '$(GOPATH)/pkg'
|
||||||
|
mkdir -p '$(GOROOT)'
|
||||||
|
shopt -s extglob
|
||||||
|
shopt -s dotglob
|
||||||
|
echo '##vso[task.prependpath]$(GOBIN)'
|
||||||
|
echo '##vso[task.prependpath]$(GOROOT)/bin'
|
||||||
|
displayName: 'Set up the Go workspace'
|
||||||
|
- script: |
|
||||||
|
go version
|
||||||
|
go get -v -d ./...
|
||||||
|
cd cmd/wails
|
||||||
|
go install
|
||||||
|
workingDirectory: '$(modulePath)'
|
||||||
|
displayName: 'Get dependencies, then build'
|
||||||
|
- script: |
|
||||||
|
wails version
|
||||||
|
workingDirectory: '$(modulePath)'
|
||||||
|
displayName: 'Check we have output'
|
||||||
|
|
||||||
|
- deployment: Mac
|
||||||
|
displayName: Mac
|
||||||
|
variables:
|
||||||
|
GOPATH: '$(Agent.BuildDirectory)/gopath' # Go workspace path
|
||||||
|
GOROOT: '$(Agent.BuildDirectory)/go' # Go installation path
|
||||||
|
GOBIN: '$(GOPATH)/bin' # Go binaries path
|
||||||
|
GOMODULE: 'on'
|
||||||
|
modulePath: '$(Agent.BuildDirectory)/wails' # Path to the module's code
|
||||||
|
pool:
|
||||||
|
vmImage: 'macOS-10.14'
|
||||||
|
environment: 'mac-dev'
|
||||||
|
strategy:
|
||||||
|
runOnce:
|
||||||
|
deploy:
|
||||||
|
steps:
|
||||||
|
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
|
||||||
|
clean: true # whether to fetch clean each time
|
||||||
|
path: wails # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
|
||||||
|
# go version 1.12.7
|
||||||
|
- script: |
|
||||||
|
wget "https://storage.googleapis.com/golang/go1.12.7.darwin-amd64.tar.gz" --output-document "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
||||||
|
tar -C '$(Agent.BuildDirectory)' -xzf "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
||||||
|
displayName: 'Install Go 1.12.7 Linux'
|
||||||
|
- script: |
|
||||||
|
mkdir -p '$(GOBIN)'
|
||||||
|
mkdir -p '$(GOPATH)/pkg'
|
||||||
|
mkdir -p '$(GOROOT)'
|
||||||
|
shopt -s extglob
|
||||||
|
shopt -s dotglob
|
||||||
|
echo '##vso[task.prependpath]$(GOBIN)'
|
||||||
|
echo '##vso[task.prependpath]$(GOROOT)/bin'
|
||||||
|
displayName: 'Set up the Go workspace'
|
||||||
|
- script: |
|
||||||
|
go version
|
||||||
|
go get -v -d ./...
|
||||||
|
cd cmd/wails
|
||||||
|
go install
|
||||||
|
workingDirectory: '$(modulePath)'
|
||||||
|
displayName: 'Get dependencies, then build'
|
||||||
|
- script: |
|
||||||
|
wails version
|
||||||
|
workingDirectory: '$(modulePath)'
|
||||||
|
displayName: 'Check we have output'
|
||||||
|
|
||||||
|
- deployment: Win
|
||||||
|
displayName: Win
|
||||||
|
variables:
|
||||||
|
GOMODULE: 'on'
|
||||||
|
modulePath: '$(Agent.BuildDirectory)/wails' # Path to the module's code
|
||||||
|
pool:
|
||||||
|
vmImage: 'windows-2019'
|
||||||
|
environment: 'win-dev'
|
||||||
|
strategy:
|
||||||
|
runOnce:
|
||||||
|
deploy:
|
||||||
|
steps:
|
||||||
|
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
|
||||||
|
clean: true # whether to fetch clean each time
|
||||||
|
path: wails # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
|
||||||
|
# Go tool installer
|
||||||
|
# Find in cache or download a specific version of Go and add it to the PATH
|
||||||
|
- task: GoTool@0
|
||||||
|
inputs:
|
||||||
|
version: '1.12.7'
|
||||||
|
goPath: '$(Agent.BuildDirectory)/go'
|
||||||
|
goBin: '$(Agent.BuildDirectory)/go/bin'
|
||||||
|
displayName: 'Set up the Go workspace'
|
||||||
|
- script: |
|
||||||
|
go version
|
||||||
|
go get -v -d ./...
|
||||||
|
cd cmd/wails
|
||||||
|
go install
|
||||||
|
workingDirectory: '$(modulePath)'
|
||||||
|
displayName: 'Get dependencies, then build'
|
||||||
|
- script: |
|
||||||
|
wails version
|
||||||
|
workingDirectory: '$(Agent.BuildDirectory)/go/bin'
|
||||||
|
displayName: 'Check we have output'
|
||||||
138
azure-pipelines.yml
Normal file
138
azure-pipelines.yml
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
# avoid double trigger by applying some rules
|
||||||
|
# start a pipeline when push to 'master' branch
|
||||||
|
trigger:
|
||||||
|
- master
|
||||||
|
# or when pull request on 'develop' branch
|
||||||
|
pr:
|
||||||
|
- develop
|
||||||
|
|
||||||
|
# for now there is only one stage 'Build'
|
||||||
|
# in the future we could use multistage strategy for releases
|
||||||
|
stages:
|
||||||
|
- stage: Build
|
||||||
|
|
||||||
|
# there are 3 jobs
|
||||||
|
# one for each os
|
||||||
|
jobs:
|
||||||
|
- deployment: Linux
|
||||||
|
displayName: Lin
|
||||||
|
variables:
|
||||||
|
GOPATH: '$(Agent.BuildDirectory)/gopath' # Go workspace path
|
||||||
|
GOROOT: '$(Agent.BuildDirectory)/go' # Go installation path
|
||||||
|
GOBIN: '$(GOPATH)/bin' # Go binaries path
|
||||||
|
GOMODULE: 'on'
|
||||||
|
modulePath: '$(Agent.BuildDirectory)/wails' # Path to the module's code
|
||||||
|
pool:
|
||||||
|
vmImage: 'Ubuntu-16.04'
|
||||||
|
environment: 'linux-dev'
|
||||||
|
strategy:
|
||||||
|
runOnce:
|
||||||
|
deploy:
|
||||||
|
steps:
|
||||||
|
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
|
||||||
|
clean: true # whether to fetch clean each time
|
||||||
|
path: wails # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
|
||||||
|
# go version 1.12.7
|
||||||
|
- script: |
|
||||||
|
wget "https://storage.googleapis.com/golang/go1.12.7.linux-amd64.tar.gz" --output-document "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
||||||
|
tar -C '$(Agent.BuildDirectory)' -xzf "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
||||||
|
displayName: 'Install Go 1.12.7 Linux'
|
||||||
|
- script: |
|
||||||
|
mkdir -p '$(GOBIN)'
|
||||||
|
mkdir -p '$(GOPATH)/pkg'
|
||||||
|
mkdir -p '$(GOROOT)'
|
||||||
|
shopt -s extglob
|
||||||
|
shopt -s dotglob
|
||||||
|
echo '##vso[task.prependpath]$(GOBIN)'
|
||||||
|
echo '##vso[task.prependpath]$(GOROOT)/bin'
|
||||||
|
displayName: 'Set up the Go workspace'
|
||||||
|
- script: |
|
||||||
|
go version
|
||||||
|
go get -v -d ./...
|
||||||
|
cd cmd/wails
|
||||||
|
go install
|
||||||
|
workingDirectory: '$(modulePath)'
|
||||||
|
displayName: 'Get dependencies, then build'
|
||||||
|
- script: |
|
||||||
|
wails version
|
||||||
|
workingDirectory: '$(modulePath)'
|
||||||
|
displayName: 'Check we have output'
|
||||||
|
|
||||||
|
- deployment: Mac
|
||||||
|
displayName: Mac
|
||||||
|
variables:
|
||||||
|
GOPATH: '$(Agent.BuildDirectory)/gopath' # Go workspace path
|
||||||
|
GOROOT: '$(Agent.BuildDirectory)/go' # Go installation path
|
||||||
|
GOBIN: '$(GOPATH)/bin' # Go binaries path
|
||||||
|
GOMODULE: 'on'
|
||||||
|
modulePath: '$(Agent.BuildDirectory)/wails' # Path to the module's code
|
||||||
|
pool:
|
||||||
|
vmImage: 'macOS-10.14'
|
||||||
|
environment: 'mac-dev'
|
||||||
|
strategy:
|
||||||
|
runOnce:
|
||||||
|
deploy:
|
||||||
|
steps:
|
||||||
|
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
|
||||||
|
clean: true # whether to fetch clean each time
|
||||||
|
path: wails # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
|
||||||
|
# go version 1.12.7
|
||||||
|
- script: |
|
||||||
|
wget "https://storage.googleapis.com/golang/go1.12.7.darwin-amd64.tar.gz" --output-document "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
||||||
|
tar -C '$(Agent.BuildDirectory)' -xzf "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
||||||
|
displayName: 'Install Go 1.12.7 Linux'
|
||||||
|
- script: |
|
||||||
|
mkdir -p '$(GOBIN)'
|
||||||
|
mkdir -p '$(GOPATH)/pkg'
|
||||||
|
mkdir -p '$(GOROOT)'
|
||||||
|
shopt -s extglob
|
||||||
|
shopt -s dotglob
|
||||||
|
echo '##vso[task.prependpath]$(GOBIN)'
|
||||||
|
echo '##vso[task.prependpath]$(GOROOT)/bin'
|
||||||
|
displayName: 'Set up the Go workspace'
|
||||||
|
- script: |
|
||||||
|
go version
|
||||||
|
go get -v -d ./...
|
||||||
|
cd cmd/wails
|
||||||
|
go install
|
||||||
|
workingDirectory: '$(modulePath)'
|
||||||
|
displayName: 'Get dependencies, then build'
|
||||||
|
- script: |
|
||||||
|
wails version
|
||||||
|
workingDirectory: '$(modulePath)'
|
||||||
|
displayName: 'Check we have output'
|
||||||
|
|
||||||
|
- deployment: Win
|
||||||
|
displayName: Win
|
||||||
|
variables:
|
||||||
|
GOMODULE: 'on'
|
||||||
|
modulePath: '$(Agent.BuildDirectory)/wails' # Path to the module's code
|
||||||
|
pool:
|
||||||
|
vmImage: 'windows-2019'
|
||||||
|
environment: 'win-dev'
|
||||||
|
strategy:
|
||||||
|
runOnce:
|
||||||
|
deploy:
|
||||||
|
steps:
|
||||||
|
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
|
||||||
|
clean: true # whether to fetch clean each time
|
||||||
|
path: wails # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
|
||||||
|
# Go tool installer
|
||||||
|
# Find in cache or download a specific version of Go and add it to the PATH
|
||||||
|
- task: GoTool@0
|
||||||
|
inputs:
|
||||||
|
version: '1.12.7'
|
||||||
|
goPath: '$(Agent.BuildDirectory)/go'
|
||||||
|
goBin: '$(Agent.BuildDirectory)/go/bin'
|
||||||
|
displayName: 'Set up the Go workspace'
|
||||||
|
- script: |
|
||||||
|
go version
|
||||||
|
go get -v -d ./...
|
||||||
|
cd cmd/wails
|
||||||
|
go install
|
||||||
|
workingDirectory: '$(modulePath)'
|
||||||
|
displayName: 'Get dependencies, then build'
|
||||||
|
- script: |
|
||||||
|
wails version
|
||||||
|
workingDirectory: '$(Agent.BuildDirectory)/go/bin'
|
||||||
|
displayName: 'Check we have output'
|
||||||
@@ -11,10 +11,9 @@ func (app *App) setupCli() *cmd.Cli {
|
|||||||
result := cmd.NewCli(app.config.Title, "Debug build")
|
result := cmd.NewCli(app.config.Title, "Debug build")
|
||||||
result.Version(cmd.Version)
|
result.Version(cmd.Version)
|
||||||
|
|
||||||
// Setup cli to handle loglevel and headless flags
|
// Setup cli to handle loglevel
|
||||||
result.
|
result.
|
||||||
StringFlag("loglevel", "Sets the log level [debug|info|error|panic|fatal]. Default debug", &app.logLevel).
|
StringFlag("loglevel", "Sets the log level [debug|info|error|panic|fatal]. Default debug", &app.logLevel).
|
||||||
// BoolFlag("headless", "Runs the app in headless mode", &app.headless).
|
|
||||||
Action(app.start)
|
Action(app.start)
|
||||||
|
|
||||||
// Banner
|
// Banner
|
||||||
File diff suppressed because one or more lines are too long
@@ -18,7 +18,7 @@ func NewGitHubHelper() *GitHubHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetVersionTags gets the list of tags on the Wails repo
|
// GetVersionTags gets the list of tags on the Wails repo
|
||||||
// It retuns a list of sorted tags in descending order
|
// It returns a list of sorted tags in descending order
|
||||||
func (g *GitHubHelper) GetVersionTags() ([]*SemanticVersion, error) {
|
func (g *GitHubHelper) GetVersionTags() ([]*SemanticVersion, error) {
|
||||||
|
|
||||||
result := []*SemanticVersion{}
|
result := []*SemanticVersion{}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
mewn "github.com/leaanthony/mewn"
|
"github.com/leaanthony/mewn"
|
||||||
"github.com/leaanthony/slicer"
|
"github.com/leaanthony/slicer"
|
||||||
"github.com/leaanthony/spinner"
|
"github.com/leaanthony/spinner"
|
||||||
)
|
)
|
||||||
@@ -249,8 +249,8 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
|
|||||||
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
|
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install the bridge library
|
// Install the runtime
|
||||||
err = InstallBridge(caller, projectDir, projectOptions)
|
err = InstallRuntime(caller, projectDir, projectOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -263,22 +263,29 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstallBridge installs the relevant bridge javascript library
|
// InstallRuntime installs the correct runtime for the type of build
|
||||||
func InstallBridge(caller string, projectDir string, projectOptions *ProjectOptions) error {
|
func InstallRuntime(caller string, projectDir string, projectOptions *ProjectOptions) error {
|
||||||
bridgeFile := "wailsbridge.prod.js"
|
if caller == "build" {
|
||||||
if caller == "serve" {
|
return InstallProdRuntime(projectDir, projectOptions)
|
||||||
bridgeFile = "wailsbridge.js"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy bridge to project
|
return InstallBridge(projectDir, projectOptions)
|
||||||
bridgeAssets := mewn.Group("../wailsruntimeassets/bridge/")
|
}
|
||||||
bridgeFileData := bridgeAssets.Bytes(bridgeFile)
|
|
||||||
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, projectOptions.FrontEnd.Bridge, "wailsbridge.js")
|
// InstallBridge installs the relevant bridge javascript library
|
||||||
err := fs.CreateFile(bridgeFileTarget, bridgeFileData)
|
func InstallBridge(projectDir string, projectOptions *ProjectOptions) error {
|
||||||
if err != nil {
|
bridgeFileData := mewn.String("../runtime/assets/bridge.js")
|
||||||
|
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "main.js")
|
||||||
|
err := fs.CreateFile(bridgeFileTarget, []byte(bridgeFileData))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstallProdRuntime installs the production runtime
|
||||||
|
func InstallProdRuntime(projectDir string, projectOptions *ProjectOptions) error {
|
||||||
|
prodInit := mewn.String("../runtime/js/runtime/init.js")
|
||||||
|
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "main.js")
|
||||||
|
err := fs.CreateFile(bridgeFileTarget, []byte(prodInit))
|
||||||
return err
|
return err
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeProject attempts to serve up the current project so that it may be connected to
|
// ServeProject attempts to serve up the current project so that it may be connected to
|
||||||
|
|||||||
180
cmd/linux.go
180
cmd/linux.go
@@ -17,74 +17,68 @@ type LinuxDistribution int
|
|||||||
const (
|
const (
|
||||||
// Unknown is the catch-all distro
|
// Unknown is the catch-all distro
|
||||||
Unknown LinuxDistribution = iota
|
Unknown LinuxDistribution = iota
|
||||||
|
// Debian distribution
|
||||||
|
Debian
|
||||||
// Ubuntu distribution
|
// Ubuntu distribution
|
||||||
Ubuntu
|
Ubuntu
|
||||||
// Arch linux distribution
|
// Arch linux distribution
|
||||||
Arch
|
Arch
|
||||||
// RedHat linux distribution
|
// CentOS linux distribution
|
||||||
RedHat
|
CentOS
|
||||||
// Debian distribution
|
// Fedora linux distribution
|
||||||
Debian
|
Fedora
|
||||||
|
// Gentoo distribution
|
||||||
|
Gentoo
|
||||||
|
// Zorin distribution
|
||||||
|
Zorin
|
||||||
|
// Parrot distribution
|
||||||
|
Parrot
|
||||||
|
// Linuxmint distribution
|
||||||
|
Linuxmint
|
||||||
|
// VoidLinux distribution
|
||||||
|
VoidLinux
|
||||||
|
// Elementary distribution
|
||||||
|
Elementary
|
||||||
|
// Kali distribution
|
||||||
|
Kali
|
||||||
)
|
)
|
||||||
|
|
||||||
// DistroInfo contains all the information relating to a linux distribution
|
// DistroInfo contains all the information relating to a linux distribution
|
||||||
type DistroInfo struct {
|
type DistroInfo struct {
|
||||||
Distribution LinuxDistribution
|
Distribution LinuxDistribution
|
||||||
|
Name string
|
||||||
|
ID string
|
||||||
Description string
|
Description string
|
||||||
Release string
|
Release string
|
||||||
Codename string
|
|
||||||
DistributorID string
|
|
||||||
DiscoveredBy string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLinuxDistroInfo returns information about the running linux distribution
|
// GetLinuxDistroInfo returns information about the running linux distribution
|
||||||
func GetLinuxDistroInfo() *DistroInfo {
|
func GetLinuxDistroInfo() *DistroInfo {
|
||||||
result := &DistroInfo{Distribution: Unknown}
|
result := &DistroInfo{
|
||||||
program := NewProgramHelper()
|
Distribution: Unknown,
|
||||||
// Does lsb_release exist?
|
ID: "unknown",
|
||||||
|
Name: "Unknown",
|
||||||
lsbRelease := program.FindProgram("lsb_release")
|
|
||||||
if lsbRelease != nil {
|
|
||||||
stdout, _, _, err := lsbRelease.Run("-a")
|
|
||||||
if err != nil {
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
result.DiscoveredBy = "lsb"
|
_, err := os.Stat("/etc/os-release")
|
||||||
for _, line := range strings.Split(stdout, "\n") {
|
if !os.IsNotExist(err) {
|
||||||
if strings.Contains(line, ":") {
|
|
||||||
// Iterate lines a
|
|
||||||
details := strings.Split(line, ":")
|
|
||||||
key := strings.TrimSpace(details[0])
|
|
||||||
value := strings.TrimSpace(details[1])
|
|
||||||
switch key {
|
|
||||||
case "Distributor ID":
|
|
||||||
result.DistributorID = value
|
|
||||||
switch value {
|
|
||||||
case "Ubuntu":
|
|
||||||
result.Distribution = Ubuntu
|
|
||||||
case "Arch", "ManjaroLinux":
|
|
||||||
result.Distribution = Arch
|
|
||||||
case "Debian":
|
|
||||||
result.Distribution = Debian
|
|
||||||
}
|
|
||||||
case "Description":
|
|
||||||
result.Description = value
|
|
||||||
case "Release":
|
|
||||||
result.Release = value
|
|
||||||
case "Codename":
|
|
||||||
result.Codename = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// check if /etc/os-release exists
|
|
||||||
} else if _, err := os.Stat("/etc/os-release"); !os.IsNotExist(err) {
|
|
||||||
// Default value
|
|
||||||
osName := "Unknown"
|
|
||||||
version := ""
|
|
||||||
// read /etc/os-release
|
|
||||||
osRelease, _ := ioutil.ReadFile("/etc/os-release")
|
osRelease, _ := ioutil.ReadFile("/etc/os-release")
|
||||||
|
result = parseOsRelease(string(osRelease))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseOsRelease parses the given os-release data and returns
|
||||||
|
// a DistroInfo struct with the details
|
||||||
|
func parseOsRelease(osRelease string) *DistroInfo {
|
||||||
|
result := &DistroInfo{Distribution: Unknown}
|
||||||
|
|
||||||
|
// Default value
|
||||||
|
osID := "unknown"
|
||||||
|
osNAME := "Unknown"
|
||||||
|
version := ""
|
||||||
|
|
||||||
// Split into lines
|
// Split into lines
|
||||||
lines := strings.Split(string(osRelease), "\n")
|
lines := strings.Split(osRelease, "\n")
|
||||||
// Iterate lines
|
// Iterate lines
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
// Split each line by the equals char
|
// Split each line by the equals char
|
||||||
@@ -94,33 +88,65 @@ func GetLinuxDistroInfo() *DistroInfo {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch splitLine[0] {
|
switch splitLine[0] {
|
||||||
|
case "ID":
|
||||||
|
osID = strings.Trim(splitLine[1], "\"")
|
||||||
case "NAME":
|
case "NAME":
|
||||||
osName = strings.Trim(splitLine[1], "\"")
|
osNAME = strings.Trim(splitLine[1], "\"")
|
||||||
case "VERSION_ID":
|
case "VERSION_ID":
|
||||||
version = strings.Trim(splitLine[1], "\"")
|
version = strings.Trim(splitLine[1], "\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// Check distro name against list of distros
|
// Check distro name against list of distros
|
||||||
result.Release = version
|
switch osID {
|
||||||
result.DiscoveredBy = "os-release"
|
case "fedora":
|
||||||
switch osName {
|
result.Distribution = Fedora
|
||||||
case "Fedora":
|
case "centos":
|
||||||
result.Distribution = RedHat
|
result.Distribution = CentOS
|
||||||
case "CentOS":
|
case "arch":
|
||||||
result.Distribution = RedHat
|
|
||||||
case "Arch Linux":
|
|
||||||
result.Distribution = Arch
|
result.Distribution = Arch
|
||||||
case "Debian GNU/Linux":
|
case "debian":
|
||||||
result.Distribution = Debian
|
result.Distribution = Debian
|
||||||
|
case "ubuntu":
|
||||||
|
result.Distribution = Ubuntu
|
||||||
|
case "gentoo":
|
||||||
|
result.Distribution = Gentoo
|
||||||
|
case "zorin":
|
||||||
|
result.Distribution = Zorin
|
||||||
|
case "parrot":
|
||||||
|
result.Distribution = Parrot
|
||||||
|
case "linuxmint":
|
||||||
|
result.Distribution = Linuxmint
|
||||||
|
case "void":
|
||||||
|
result.Distribution = VoidLinux
|
||||||
|
case "elementary":
|
||||||
|
result.Distribution = Elementary
|
||||||
|
case "kali":
|
||||||
|
result.Distribution = Kali
|
||||||
default:
|
default:
|
||||||
result.Distribution = Unknown
|
result.Distribution = Unknown
|
||||||
result.DistributorID = osName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.Name = osNAME
|
||||||
|
result.ID = osID
|
||||||
|
result.Release = version
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckPkgInstalled is all functions that use local programs to see if a package is installed
|
||||||
|
type CheckPkgInstalled func(string) (bool, error)
|
||||||
|
|
||||||
|
// EqueryInstalled uses equery to see if a package is installed
|
||||||
|
func EqueryInstalled(packageName string) (bool, error) {
|
||||||
|
program := NewProgramHelper()
|
||||||
|
equery := program.FindProgram("equery")
|
||||||
|
if equery == nil {
|
||||||
|
return false, fmt.Errorf("cannont check dependencies: equery not found")
|
||||||
|
}
|
||||||
|
_, _, exitCode, _ := equery.Run("l", packageName)
|
||||||
|
return exitCode == 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
// DpkgInstalled uses dpkg to see if a package is installed
|
// DpkgInstalled uses dpkg to see if a package is installed
|
||||||
func DpkgInstalled(packageName string) (bool, error) {
|
func DpkgInstalled(packageName string) (bool, error) {
|
||||||
program := NewProgramHelper()
|
program := NewProgramHelper()
|
||||||
@@ -143,6 +169,17 @@ func PacmanInstalled(packageName string) (bool, error) {
|
|||||||
return exitCode == 0, nil
|
return exitCode == 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XbpsInstalled uses pacman to see if a package is installed.
|
||||||
|
func XbpsInstalled(packageName string) (bool, error) {
|
||||||
|
program := NewProgramHelper()
|
||||||
|
xbpsQuery := program.FindProgram("xbps-query")
|
||||||
|
if xbpsQuery == nil {
|
||||||
|
return false, fmt.Errorf("cannot check dependencies: xbps-query not found")
|
||||||
|
}
|
||||||
|
_, _, exitCode, _ := xbpsQuery.Run("-S", packageName)
|
||||||
|
return exitCode == 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
// RpmInstalled uses rpm to see if a package is installed
|
// RpmInstalled uses rpm to see if a package is installed
|
||||||
func RpmInstalled(packageName string) (bool, error) {
|
func RpmInstalled(packageName string) (bool, error) {
|
||||||
program := NewProgramHelper()
|
program := NewProgramHelper()
|
||||||
@@ -156,18 +193,18 @@ func RpmInstalled(packageName string) (bool, error) {
|
|||||||
|
|
||||||
// RequestSupportForDistribution promts the user to submit a request to support their
|
// RequestSupportForDistribution promts the user to submit a request to support their
|
||||||
// currently unsupported distribution
|
// currently unsupported distribution
|
||||||
func RequestSupportForDistribution(distroInfo *DistroInfo, libraryName string) error {
|
func RequestSupportForDistribution(distroInfo *DistroInfo) error {
|
||||||
var logger = NewLogger()
|
var logger = NewLogger()
|
||||||
defaultError := fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, libraryName)
|
defaultError := fmt.Errorf("unable to check libraries on distribution '%s'", distroInfo.Name)
|
||||||
|
|
||||||
logger.Yellow("Distribution '%s' is not currently supported, but we would love to!", distroInfo.DistributorID)
|
logger.Yellow("Distribution '%s' is not currently supported, but we would love to!", distroInfo.Name)
|
||||||
q := fmt.Sprintf("Would you like to submit a request to support distribution '%s'?", distroInfo.DistributorID)
|
q := fmt.Sprintf("Would you like to submit a request to support distribution '%s'?", distroInfo.Name)
|
||||||
result := Prompt(q, "yes")
|
result := Prompt(q, "yes")
|
||||||
if strings.ToLower(result) != "yes" {
|
if strings.ToLower(result) != "yes" {
|
||||||
return defaultError
|
return defaultError
|
||||||
}
|
}
|
||||||
|
|
||||||
title := fmt.Sprintf("Support Distribution '%s'", distroInfo.DistributorID)
|
title := fmt.Sprintf("Support Distribution '%s'", distroInfo.Name)
|
||||||
|
|
||||||
var str strings.Builder
|
var str strings.Builder
|
||||||
|
|
||||||
@@ -182,16 +219,15 @@ func RequestSupportForDistribution(distroInfo *DistroInfo, libraryName string) e
|
|||||||
str.WriteString(fmt.Sprintf("| Platform | %s |\n", runtime.GOOS))
|
str.WriteString(fmt.Sprintf("| Platform | %s |\n", runtime.GOOS))
|
||||||
str.WriteString(fmt.Sprintf("| Arch | %s |\n", runtime.GOARCH))
|
str.WriteString(fmt.Sprintf("| Arch | %s |\n", runtime.GOARCH))
|
||||||
str.WriteString(fmt.Sprintf("| GO111MODULE | %s |\n", gomodule))
|
str.WriteString(fmt.Sprintf("| GO111MODULE | %s |\n", gomodule))
|
||||||
str.WriteString(fmt.Sprintf("| Distribution ID | %s |\n", distroInfo.DistributorID))
|
str.WriteString(fmt.Sprintf("| Distribution ID | %s |\n", distroInfo.ID))
|
||||||
|
str.WriteString(fmt.Sprintf("| Distribution Name | %s |\n", distroInfo.Name))
|
||||||
str.WriteString(fmt.Sprintf("| Distribution Version | %s |\n", distroInfo.Release))
|
str.WriteString(fmt.Sprintf("| Distribution Version | %s |\n", distroInfo.Release))
|
||||||
str.WriteString(fmt.Sprintf("| Discovered by | %s |\n", distroInfo.DiscoveredBy))
|
|
||||||
|
|
||||||
body := fmt.Sprintf("**Description**\nDistribution '%s' is currently unsupported.\n\n**Further Information**\n\n%s\n\n*Please add any extra information here, EG: libraries that are needed to make the distribution work, or commands to install them*", distroInfo.DistributorID, str.String())
|
body := fmt.Sprintf("**Description**\nDistribution '%s' is currently unsupported.\n\n**Further Information**\n\n%s\n\n*Please add any extra information here, EG: libraries that are needed to make the distribution work, or commands to install them*", distroInfo.ID, str.String())
|
||||||
fullURL := "https://github.com/wailsapp/wails/issues/new?"
|
fullURL := "https://github.com/wailsapp/wails/issues/new?"
|
||||||
params := "title=" + title + "&body=" + body
|
params := "title=" + title + "&body=" + body
|
||||||
|
|
||||||
fmt.Println("Opening browser to file request.")
|
fmt.Println("Opening browser to file request.")
|
||||||
browser.OpenURL(fullURL + url.PathEscape(params))
|
browser.OpenURL(fullURL + url.PathEscape(params))
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
26
cmd/linux_test.go
Normal file
26
cmd/linux_test.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestUbuntuDetection(t *testing.T) {
|
||||||
|
osrelease := `
|
||||||
|
NAME="Ubuntu"
|
||||||
|
VERSION="18.04.2 LTS (Bionic Beaver)"
|
||||||
|
ID=ubuntu
|
||||||
|
ID_LIKE=debian
|
||||||
|
PRETTY_NAME="Ubuntu 18.04.2 LTS"
|
||||||
|
VERSION_ID="18.04"
|
||||||
|
HOME_URL="https://www.ubuntu.com/"
|
||||||
|
SUPPORT_URL="https://help.ubuntu.com/"
|
||||||
|
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
|
||||||
|
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
|
||||||
|
VERSION_CODENAME=bionic
|
||||||
|
UBUNTU_CODENAME=bionic
|
||||||
|
`
|
||||||
|
|
||||||
|
result := parseOsRelease(osrelease)
|
||||||
|
if result.Distribution != Ubuntu {
|
||||||
|
t.Errorf("expected 'Ubuntu' ID but got '%d'", result.Distribution)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
91
cmd/linuxdb.go
Normal file
91
cmd/linuxdb.go
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/leaanthony/mewn"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LinuxDB is the database for linux distribution data.
|
||||||
|
type LinuxDB struct {
|
||||||
|
Distributions map[string]*Distribution `yaml:"distributions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distribution holds the os-release ID and a map of releases.
|
||||||
|
type Distribution struct {
|
||||||
|
ID string `yaml:"id"`
|
||||||
|
Releases map[string]*Release `yaml:"releases"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRelease attempts to return the specific Release information
|
||||||
|
// for the given release name. If there is no specific match, the
|
||||||
|
// default release data is returned.
|
||||||
|
func (d *Distribution) GetRelease(version string) *Release {
|
||||||
|
result := d.Releases[version]
|
||||||
|
if result == nil {
|
||||||
|
result = d.Releases["default"]
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release holds the name and version of the release as given by
|
||||||
|
// os-release. Programs is a slice of dependant programs required
|
||||||
|
// to be present on the local installation for Wails to function.
|
||||||
|
// Libraries is a slice of libraries that must be present for Wails
|
||||||
|
// applications to compile.
|
||||||
|
type Release struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Version string `yaml:"version"`
|
||||||
|
GccVersionCommand string `yaml:"gccversioncommand"`
|
||||||
|
Programs []*Prerequisite `yaml:"programs"`
|
||||||
|
Libraries []*Prerequisite `yaml:"libraries"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prerequisite is a simple struct containing a program/library name
|
||||||
|
// plus the distribution specific help text indicating how to install
|
||||||
|
// it.
|
||||||
|
type Prerequisite struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Help string `yaml:"help,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load will load the given filename from disk and attempt to
|
||||||
|
// import the data into the LinuxDB.
|
||||||
|
func (l *LinuxDB) Load(filename string) error {
|
||||||
|
if fs.FileExists(filename) {
|
||||||
|
data, err := fs.LoadAsBytes(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return l.ImportData(data)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportData will unmarshal the given YAML formatted data
|
||||||
|
// into the LinuxDB
|
||||||
|
func (l *LinuxDB) ImportData(data []byte) error {
|
||||||
|
return yaml.Unmarshal(data, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDistro returns the Distribution information for the
|
||||||
|
// given distribution name. If the distribution is not supported,
|
||||||
|
// nil is returned.
|
||||||
|
func (l *LinuxDB) GetDistro(distro string) *Distribution {
|
||||||
|
return l.Distributions[distro]
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLinuxDB creates a new LinuxDB instance from the bundled
|
||||||
|
// linuxdb.yaml file.
|
||||||
|
func NewLinuxDB() *LinuxDB {
|
||||||
|
data := mewn.Bytes("./linuxdb.yaml")
|
||||||
|
result := LinuxDB{
|
||||||
|
Distributions: make(map[string]*Distribution),
|
||||||
|
}
|
||||||
|
err := result.ImportData(data)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return &result
|
||||||
|
}
|
||||||
170
cmd/linuxdb.yaml
Normal file
170
cmd/linuxdb.yaml
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
---
|
||||||
|
distributions:
|
||||||
|
debian:
|
||||||
|
id: debian
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
name: Debian
|
||||||
|
version: default
|
||||||
|
gccversioncommand: &gccdumpversion -dumpversion
|
||||||
|
programs: &debiandefaultprograms
|
||||||
|
- name: gcc
|
||||||
|
help: Please install with `sudo apt-get install build-essential` and try again
|
||||||
|
- name: pkg-config
|
||||||
|
help: Please install with `sudo apt-get install pkg-config` and try again
|
||||||
|
- name: npm
|
||||||
|
help: Please install with `curl -sL https://deb.nodesource.com/setup_12.x | sudo bash - && sudo apt-get install -y nodejs` and try again
|
||||||
|
libraries: &debiandefaultlibraries
|
||||||
|
- name: libgtk-3-dev
|
||||||
|
help: Please install with `sudo apt-get install libgtk-3-dev` and try again
|
||||||
|
- name: libwebkit2gtk-4.0-dev
|
||||||
|
help: Please install with `sudo apt-get install libwebkit2gtk-4.0-dev` and try again
|
||||||
|
ubuntu:
|
||||||
|
id: ubuntu
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Ubuntu
|
||||||
|
gccversioncommand: &gccdumpfullversion -dumpfullversion
|
||||||
|
programs: *debiandefaultprograms
|
||||||
|
libraries: *debiandefaultlibraries
|
||||||
|
kali:
|
||||||
|
id: kali
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Kali GNU/Linux
|
||||||
|
gccversioncommand: *gccdumpfullversion
|
||||||
|
programs: *debiandefaultprograms
|
||||||
|
libraries: *debiandefaultlibraries
|
||||||
|
parrot:
|
||||||
|
id: parrot
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Parrot GNU/Linux
|
||||||
|
gccversioncommand: *gccdumpversion
|
||||||
|
programs: *debiandefaultprograms
|
||||||
|
libraries: *debiandefaultlibraries
|
||||||
|
zorin:
|
||||||
|
id: zorin
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Zorin
|
||||||
|
gccversioncommand: *gccdumpversion
|
||||||
|
programs: *debiandefaultprograms
|
||||||
|
libraries: *debiandefaultlibraries
|
||||||
|
linuxmint:
|
||||||
|
id: linuxmint
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Linux Mint
|
||||||
|
gccversioncommand: *gccdumpversion
|
||||||
|
programs: *debiandefaultprograms
|
||||||
|
libraries: *debiandefaultlibraries
|
||||||
|
elementary:
|
||||||
|
id: elementary
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: elementary OS
|
||||||
|
gccversioncommand: *gccdumpfullversion
|
||||||
|
programs: *debiandefaultprograms
|
||||||
|
libraries: *debiandefaultlibraries
|
||||||
|
void:
|
||||||
|
id: void
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: VoidLinux
|
||||||
|
gccversioncommand: *gccdumpversion
|
||||||
|
programs:
|
||||||
|
- name: gcc
|
||||||
|
help: Please install with `xbps-install base-devel` and try again
|
||||||
|
- name: pkg-config
|
||||||
|
help: Please install with `xbps-install pkg-config` and try again
|
||||||
|
- name: npm
|
||||||
|
help: Please install with `xbps-install nodejs` and try again
|
||||||
|
libraries:
|
||||||
|
- name: gtk+3-devel
|
||||||
|
help: Please install with `xbps-install gtk+3-devel` and try again
|
||||||
|
- name: webkit2gtk-devel
|
||||||
|
help: Please install with `xbps-install webkit2gtk-devel` and try again
|
||||||
|
centos:
|
||||||
|
id: centos
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: CentOS Linux
|
||||||
|
gccversioncommand: *gccdumpversion
|
||||||
|
programs:
|
||||||
|
- name: gcc
|
||||||
|
help: Please install with `sudo yum install gcc-c++ make` and try again
|
||||||
|
- name: pkg-config
|
||||||
|
help: Please install with `sudo yum install pkgconf-pkg-config` and try again
|
||||||
|
- name: npm
|
||||||
|
help: Please install with `sudo yum install epel-release && sudo yum install nodejs` and try again
|
||||||
|
libraries:
|
||||||
|
- name: gtk3-devel
|
||||||
|
help: Please install with `sudo yum install gtk3-devel` and try again
|
||||||
|
- name: webkitgtk3-devel
|
||||||
|
help: Please install with `sudo yum install webkitgtk3-devel` and try again
|
||||||
|
fedora:
|
||||||
|
id: fedora
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Fedora
|
||||||
|
gccversioncommand: *gccdumpfullversion
|
||||||
|
programs:
|
||||||
|
- name: gcc
|
||||||
|
help: Please install with `sudo yum install gcc-c++ make` and try again
|
||||||
|
- name: pkg-config
|
||||||
|
help: Please install with `sudo yum install pkgconf-pkg-config` and try again
|
||||||
|
- name: npm
|
||||||
|
help: Please install `sudo yum install nodejs` and try again
|
||||||
|
libraries:
|
||||||
|
- name: gtk3-devel
|
||||||
|
help: Please install with `sudo yum install gtk3-devel` and try again
|
||||||
|
- name: webkit2gtk3-devel
|
||||||
|
help: Please install with `sudo yum install webkit2gtk3-devel` and try again
|
||||||
|
arch:
|
||||||
|
id: arch
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Arch Linux
|
||||||
|
gccversioncommand: *gccdumpversion
|
||||||
|
programs:
|
||||||
|
- name: gcc
|
||||||
|
help: Please install with `sudo pacman -S gcc` and try again
|
||||||
|
- name: pkgconf
|
||||||
|
help: Please install with `sudo pacman -S pkgconf` and try again
|
||||||
|
- name: npm
|
||||||
|
help: Please install with `sudo pacman -S npm` and try again
|
||||||
|
libraries:
|
||||||
|
- name: gtk3
|
||||||
|
help: Please install with `sudo pacman -S gtk3` and try again
|
||||||
|
- name: webkit2gtk
|
||||||
|
help: Please install with `sudo pacman -S webkit2gtk` and try again
|
||||||
|
gentoo:
|
||||||
|
id: gentoo
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Gentoo
|
||||||
|
gccversioncommand: *gccdumpversion
|
||||||
|
programs:
|
||||||
|
- name: gcc
|
||||||
|
help: Please install using your system's package manager
|
||||||
|
- name: pkg-config
|
||||||
|
help: Please install using your system's package manager
|
||||||
|
- name: npm
|
||||||
|
help: Please install using your system's package manager
|
||||||
|
libraries:
|
||||||
|
- name: gtk+:3
|
||||||
|
help: Please install with `sudo emerge gtk+:3` and try again
|
||||||
|
- name: webkit-gtk
|
||||||
|
help: Please install with `sudo emerge webkit-gtk` and try again
|
||||||
81
cmd/linuxdb_test.go
Normal file
81
cmd/linuxdb_test.go
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestNewLinuxDB(t *testing.T) {
|
||||||
|
_ = NewLinuxDB()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKnownDistro(t *testing.T) {
|
||||||
|
var linuxDB = NewLinuxDB()
|
||||||
|
result := linuxDB.GetDistro("ubuntu")
|
||||||
|
if result == nil {
|
||||||
|
t.Error("Cannot get distro 'ubuntu'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnknownDistro(t *testing.T) {
|
||||||
|
var linuxDB = NewLinuxDB()
|
||||||
|
result := linuxDB.GetDistro("unknown")
|
||||||
|
if result != nil {
|
||||||
|
t.Error("Should get nil for distribution 'unknown'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDefaultRelease(t *testing.T) {
|
||||||
|
var linuxDB = NewLinuxDB()
|
||||||
|
result := linuxDB.GetDistro("ubuntu")
|
||||||
|
if result == nil {
|
||||||
|
t.Error("Cannot get distro 'ubuntu'")
|
||||||
|
}
|
||||||
|
|
||||||
|
release := result.GetRelease("default")
|
||||||
|
if release == nil {
|
||||||
|
t.Error("Cannot get release 'default' for distro 'ubuntu'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnknownRelease(t *testing.T) {
|
||||||
|
var linuxDB = NewLinuxDB()
|
||||||
|
result := linuxDB.GetDistro("ubuntu")
|
||||||
|
if result == nil {
|
||||||
|
t.Error("Cannot get distro 'ubuntu'")
|
||||||
|
}
|
||||||
|
|
||||||
|
release := result.GetRelease("16.04")
|
||||||
|
if release == nil {
|
||||||
|
t.Error("Failed to get release 'default' for unknown release version '16.04'")
|
||||||
|
}
|
||||||
|
|
||||||
|
if release.Version != "default" {
|
||||||
|
t.Errorf("Got version '%s' instead of 'default' for unknown release version '16.04'", result.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetPrerequisites(t *testing.T) {
|
||||||
|
var linuxDB = NewLinuxDB()
|
||||||
|
result := linuxDB.GetDistro("debian")
|
||||||
|
if result == nil {
|
||||||
|
t.Error("Cannot get distro 'debian'")
|
||||||
|
}
|
||||||
|
|
||||||
|
release := result.GetRelease("default")
|
||||||
|
if release == nil {
|
||||||
|
t.Error("Failed to get release 'default' for unknown release version '16.04'")
|
||||||
|
}
|
||||||
|
|
||||||
|
if release.Version != "default" {
|
||||||
|
t.Errorf("Got version '%s' instead of 'default' for unknown release version '16.04'", result.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if release.Name != "Debian" {
|
||||||
|
t.Errorf("Got Release Name '%s' instead of 'debian' for unknown release version '16.04'", release.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(release.Programs) != 3 {
|
||||||
|
t.Errorf("Expected %d programs for unknown release version '16.04'", len(release.Programs))
|
||||||
|
}
|
||||||
|
if len(release.Libraries) != 2 {
|
||||||
|
t.Errorf("Expected %d libraries for unknown release version '16.04'", len(release.Libraries))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,13 +5,6 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Prerequisite defines a Prerequisite!
|
|
||||||
type Prerequisite struct {
|
|
||||||
Name string
|
|
||||||
Help string
|
|
||||||
Path string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPrerequisite(name, help string) *Prerequisite {
|
func newPrerequisite(name, help string) *Prerequisite {
|
||||||
return &Prerequisite{Name: name, Help: help}
|
return &Prerequisite{Name: name, Help: help}
|
||||||
}
|
}
|
||||||
@@ -48,16 +41,13 @@ func getRequiredProgramsOSX() *Prerequisites {
|
|||||||
func getRequiredProgramsLinux() *Prerequisites {
|
func getRequiredProgramsLinux() *Prerequisites {
|
||||||
result := &Prerequisites{}
|
result := &Prerequisites{}
|
||||||
distroInfo := GetLinuxDistroInfo()
|
distroInfo := GetLinuxDistroInfo()
|
||||||
switch distroInfo.Distribution {
|
if distroInfo.Distribution != Unknown {
|
||||||
case Ubuntu, Debian:
|
var linuxDB = NewLinuxDB()
|
||||||
result.Add(newPrerequisite("gcc", "Please install with `sudo apt install build-essentials` and try again"))
|
distro := linuxDB.GetDistro(distroInfo.ID)
|
||||||
result.Add(newPrerequisite("pkg-config", "Please install with `sudo apt install pkg-config` and try again"))
|
release := distro.GetRelease(distroInfo.Release)
|
||||||
result.Add(newPrerequisite("npm", "Please install with `sudo snap install node --channel=12/stable --classic` and try again"))
|
for _, program := range release.Programs {
|
||||||
default:
|
result.Add(program)
|
||||||
result.Add(newPrerequisite("gcc", "Please install with your system package manager and try again"))
|
}
|
||||||
result.Add(newPrerequisite("pkg-config", "Please install with your system package manager and try again"))
|
|
||||||
result.Add(newPrerequisite("npm", "Please install from https://nodejs.org/en/download/ and try again"))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -91,20 +81,15 @@ func getRequiredLibrariesOSX() (*Prerequisites, error) {
|
|||||||
|
|
||||||
func getRequiredLibrariesLinux() (*Prerequisites, error) {
|
func getRequiredLibrariesLinux() (*Prerequisites, error) {
|
||||||
result := &Prerequisites{}
|
result := &Prerequisites{}
|
||||||
|
// The Linux Distribution DB
|
||||||
distroInfo := GetLinuxDistroInfo()
|
distroInfo := GetLinuxDistroInfo()
|
||||||
switch distroInfo.Distribution {
|
if distroInfo.Distribution != Unknown {
|
||||||
case Ubuntu:
|
var linuxDB = NewLinuxDB()
|
||||||
result.Add(newPrerequisite("libgtk-3-dev", "Please install with `sudo apt install libgtk-3-dev` and try again"))
|
distro := linuxDB.GetDistro(distroInfo.ID)
|
||||||
result.Add(newPrerequisite("libwebkit2gtk-4.0-dev", "Please install with `sudo apt install libwebkit2gtk-4.0-dev` and try again"))
|
release := distro.GetRelease(distroInfo.Release)
|
||||||
case Arch:
|
for _, library := range release.Libraries {
|
||||||
result.Add(newPrerequisite("gtk3", "Please install with `sudo pacman -S gtk3` and try again"))
|
result.Add(library)
|
||||||
result.Add(newPrerequisite("webkit2gtk", "Please install with `sudo pacman -S webkit2gtk` and try again"))
|
}
|
||||||
case RedHat:
|
|
||||||
result.Add(newPrerequisite("gtk3-devel", "Please install with `sudo yum install gtk3-devel` and try again"))
|
|
||||||
result.Add(newPrerequisite("webkit2gtk3-devel", "Please install with `sudo yum install webkit2gtk3-devel` and try again"))
|
|
||||||
default:
|
|
||||||
result.Add(newPrerequisite("libgtk-3-dev", "Please install with your system package manager and try again"))
|
|
||||||
result.Add(newPrerequisite("libwebkit2gtk-4.0-dev", "Please install with your system package manager and try again"))
|
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,14 +117,15 @@ func (p *ProgramHelper) RunCommandArray(args []string, dir ...string) error {
|
|||||||
}
|
}
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
var stderr string
|
var stderr string
|
||||||
// fmt.Printf("RunCommandArray = %s %+v\n", program, args)
|
var stdout string
|
||||||
if len(dir) > 0 {
|
if len(dir) > 0 {
|
||||||
_, stderr, err = p.shell.RunInDirectory(dir[0], program, args...)
|
stdout, stderr, err = p.shell.RunInDirectory(dir[0], program, args...)
|
||||||
} else {
|
} else {
|
||||||
_, stderr, err = p.shell.Run(program, args...)
|
stdout, stderr, err = p.shell.Run(program, args...)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(stderr)
|
fmt.Println(stderr)
|
||||||
|
fmt.Println(stdout)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/leaanthony/slicer"
|
"github.com/leaanthony/slicer"
|
||||||
@@ -111,9 +112,9 @@ func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions {
|
|||||||
Description: "Enter your project description",
|
Description: "Enter your project description",
|
||||||
Version: "0.1.0",
|
Version: "0.1.0",
|
||||||
BinaryName: "",
|
BinaryName: "",
|
||||||
system: NewSystemHelper(),
|
system: ph.system,
|
||||||
log: NewLogger(),
|
log: ph.log,
|
||||||
templates: NewTemplateHelper(),
|
templates: ph.templates,
|
||||||
Author: &author{},
|
Author: &author{},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +185,13 @@ func (po *ProjectOptions) PromptForInputs() error {
|
|||||||
po.selectedTemplate = templateDetails[po.Template]
|
po.selectedTemplate = templateDetails[po.Template]
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
for _, templateDetail := range templateDetails {
|
keys := make([]string, 0)
|
||||||
|
for k := range templateDetails {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
for _, k := range keys {
|
||||||
|
templateDetail := templateDetails[k]
|
||||||
templateList.Add(templateDetail)
|
templateList.Add(templateDetail)
|
||||||
options.Add(fmt.Sprintf("%s - %s", templateDetail.Metadata.Name, templateDetail.Metadata.ShortDescription))
|
options.Add(fmt.Sprintf("%s - %s", templateDetail.Metadata.Name, templateDetail.Metadata.ShortDescription))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -20,11 +19,7 @@ func Prompt(question string, defaultValue ...string) string {
|
|||||||
fmt.Printf(question + ": ")
|
fmt.Printf(question + ": ")
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
input, _ := reader.ReadString('\n')
|
input, _ := reader.ReadString('\n')
|
||||||
EOL := "\n"
|
input = strings.TrimSpace(input)
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
EOL = "\r\n"
|
|
||||||
}
|
|
||||||
input = strings.Replace(input, EOL, "", -1)
|
|
||||||
|
|
||||||
if input != "" {
|
if input != "" {
|
||||||
answer = input
|
answer = input
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/masterminds/semver"
|
"github.com/Masterminds/semver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SemanticVersion is a struct containing a semantic version
|
// SemanticVersion is a struct containing a semantic version
|
||||||
|
|||||||
@@ -269,44 +269,35 @@ func CheckDependencies(logger *Logger) (bool, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var libraryChecker CheckPkgInstalled
|
||||||
distroInfo := GetLinuxDistroInfo()
|
distroInfo := GetLinuxDistroInfo()
|
||||||
for _, library := range *requiredLibraries {
|
|
||||||
switch distroInfo.Distribution {
|
switch distroInfo.Distribution {
|
||||||
case Ubuntu, Debian:
|
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali:
|
||||||
installed, err := DpkgInstalled(library.Name)
|
libraryChecker = DpkgInstalled
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if !installed {
|
|
||||||
errors = true
|
|
||||||
logger.Error("Library '%s' not found. %s", library.Name, library.Help)
|
|
||||||
} else {
|
|
||||||
logger.Green("Library '%s' installed.", library.Name)
|
|
||||||
}
|
|
||||||
case Arch:
|
case Arch:
|
||||||
installed, err := PacmanInstalled(library.Name)
|
libraryChecker = PacmanInstalled
|
||||||
if err != nil {
|
case CentOS, Fedora:
|
||||||
return false, err
|
libraryChecker = RpmInstalled
|
||||||
}
|
case Gentoo:
|
||||||
if !installed {
|
libraryChecker = EqueryInstalled
|
||||||
errors = true
|
case VoidLinux:
|
||||||
logger.Error("Library '%s' not found. %s", library.Name, library.Help)
|
libraryChecker = XbpsInstalled
|
||||||
} else {
|
|
||||||
logger.Green("Library '%s' installed.", library.Name)
|
|
||||||
}
|
|
||||||
case RedHat:
|
|
||||||
installed, err := RpmInstalled(library.Name)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if !installed {
|
|
||||||
errors = true
|
|
||||||
logger.Error("Library '%s' not found. %s", library.Name, library.Help)
|
|
||||||
} else {
|
|
||||||
logger.Green("Library '%s' installed.", library.Name)
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return false, RequestSupportForDistribution(distroInfo, library.Name)
|
return false, RequestSupportForDistribution(distroInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, library := range *requiredLibraries {
|
||||||
|
installed, err := libraryChecker(library.Name)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !installed {
|
||||||
|
errors = true
|
||||||
|
logger.Error("Library '%s' not found. %s", library.Name, library.Help)
|
||||||
|
} else {
|
||||||
|
logger.Green("Library '%s' installed.", library.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ func NewTemplateHelper() *TemplateHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsValidTemplate returns true if the given tempalte name resides on disk
|
// IsValidTemplate returns true if the given template name resides on disk
|
||||||
func (t *TemplateHelper) IsValidTemplate(templateName string) bool {
|
func (t *TemplateHelper) IsValidTemplate(templateName string) bool {
|
||||||
pathToTemplate := filepath.Join(t.templateDir.fullPath, templateName)
|
pathToTemplate := filepath.Join(t.templateDir.fullPath, templateName)
|
||||||
return t.fs.DirExists(pathToTemplate)
|
return t.fs.DirExists(pathToTemplate)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"@angular/platform-browser": "~8.0.1",
|
"@angular/platform-browser": "~8.0.1",
|
||||||
"@angular/platform-browser-dynamic": "~8.0.1",
|
"@angular/platform-browser-dynamic": "~8.0.1",
|
||||||
"@angular/router": "~8.0.1",
|
"@angular/router": "~8.0.1",
|
||||||
|
"@wailsapp/runtime": "^1.0.0",
|
||||||
"ngx-build-plus": "^8.0.3",
|
"ngx-build-plus": "^8.0.3",
|
||||||
"rxjs": "~6.4.0",
|
"rxjs": "~6.4.0",
|
||||||
"tslib": "^1.9.0",
|
"tslib": "^1.9.0",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Component } from '@angular/core';
|
|||||||
styleUrls: ['./app.component.css']
|
styleUrls: ['./app.component.css']
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
title = '{{.Name}}';
|
title = 'my-app';
|
||||||
|
|
||||||
clickMessage = '';
|
clickMessage = '';
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>{{.Name}}</title>
|
<title>my-app</title>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import { environment } from './environments/environment';
|
|||||||
|
|
||||||
import 'zone.js'
|
import 'zone.js'
|
||||||
|
|
||||||
import Bridge from './wailsbridge';
|
import Wails from '@wailsapp/runtime';
|
||||||
|
|
||||||
if (environment.production) {
|
if (environment.production) {
|
||||||
enableProdMode();
|
enableProdMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
Bridge.Start(() => {
|
Wails.Init(() => {
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||||
.catch(err => console.error(err));
|
.catch(err => console.error(err));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Angular",
|
"name": "Angular",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"shortdescription": "Angular 8 template",
|
"shortdescription": "Angular 8 template (Requires node 10.8+)",
|
||||||
"description": "Angular projects w/ @angular/cli - Note: in order to reach the cli use npx like this: npx ng",
|
"description": "Angular projects w/ @angular/cli - Note: in order to reach the cli use npx like this: npx ng",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,10 +4,12 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"core-js": "^3.1.4",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
"wails-react-scripts": "3.0.1-2",
|
"@wailsapp/wails-react-scripts": "3.0.1-2",
|
||||||
"react-modal": "3.8.1"
|
"react-modal": "3.8.1",
|
||||||
|
"@wailsapp/runtime": "^1.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
import 'core-js/stable';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
import Bridge from "./wailsbridge";
|
import Wails from '@wailsapp/runtime';
|
||||||
|
|
||||||
Bridge.Start(() => {
|
Wails.Init(() => {
|
||||||
ReactDOM.render(<App />, document.getElementById('app'));
|
ReactDOM.render(<App />, document.getElementById('app'));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^2.6.4",
|
"core-js": "^2.6.4",
|
||||||
"vue": "^2.5.22"
|
"vue": "^2.5.22",
|
||||||
|
"@wailsapp/runtime": "^1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^3.4.0",
|
"@vue/cli-plugin-babel": "^3.4.0",
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import Vue from "vue";
|
import Vue from 'vue';
|
||||||
import App from "./App.vue";
|
import App from './App.vue';
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
Vue.config.devtools = true;
|
Vue.config.devtools = true;
|
||||||
|
|
||||||
import Bridge from "./wailsbridge";
|
import Wails from '@wailsapp/runtime';
|
||||||
|
|
||||||
Bridge.Start(() => {
|
Wails.Init(() => {
|
||||||
new Vue({
|
new Vue({
|
||||||
render: h => h(App)
|
render: h => h(App)
|
||||||
}).$mount("#app");
|
}).$mount('#app');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
Wails Bridge (c) 2019-present Lea Anthony
|
|
||||||
|
|
||||||
This prod version is to get around having to rewrite your code
|
|
||||||
for production. When doing a release build, this file will be used
|
|
||||||
instead of the full version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default {
|
|
||||||
// The main function
|
|
||||||
// Passes the main Wails object to the callback if given.
|
|
||||||
Start: function (callback) {
|
|
||||||
if (callback) {
|
|
||||||
window.wails.Events.On("wails:ready", callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -12,7 +12,8 @@
|
|||||||
"core-js": "^2.6.4",
|
"core-js": "^2.6.4",
|
||||||
"material-design-icons-iconfont": "^5.0.1",
|
"material-design-icons-iconfont": "^5.0.1",
|
||||||
"vue": "^2.5.22",
|
"vue": "^2.5.22",
|
||||||
"vuetify": "^1.5.14"
|
"vuetify": "^1.5.14",
|
||||||
|
"@wailsapp/runtime": "^1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^3.4.0",
|
"@vue/cli-plugin-babel": "^3.4.0",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'babel-polyfill';
|
import 'babel-polyfill';
|
||||||
import Vue from "vue";
|
import Vue from 'vue';
|
||||||
|
|
||||||
// Setup Vuetify
|
// Setup Vuetify
|
||||||
import Vuetify from 'vuetify';
|
import Vuetify from 'vuetify';
|
||||||
@@ -7,15 +7,15 @@ Vue.use(Vuetify);
|
|||||||
import 'vuetify/dist/vuetify.min.css';
|
import 'vuetify/dist/vuetify.min.css';
|
||||||
import 'material-design-icons-iconfont';
|
import 'material-design-icons-iconfont';
|
||||||
|
|
||||||
import App from "./App.vue";
|
import App from './App.vue';
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
Vue.config.devtools = true;
|
Vue.config.devtools = true;
|
||||||
|
|
||||||
import Bridge from "./wailsbridge";
|
import Wails from '@wailsapp/runtime';
|
||||||
|
|
||||||
Bridge.Start(() => {
|
Wails.Init(() => {
|
||||||
new Vue({
|
new Vue({
|
||||||
render: h => h(App)
|
render: h => h(App)
|
||||||
}).$mount("#app");
|
}).$mount('#app');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
// Version - Wails version
|
// Version - Wails version
|
||||||
const Version = "v0.16.4-pre"
|
const Version = "v0.17.14-pre"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/cmd"
|
"github.com/wailsapp/wails/cmd"
|
||||||
@@ -24,7 +23,7 @@ func init() {
|
|||||||
|
|
||||||
system := cmd.NewSystemHelper()
|
system := cmd.NewSystemHelper()
|
||||||
err = system.Initialise()
|
err = system.Initialise()
|
||||||
if err == nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,23 +32,9 @@ Create your first project by running 'wails init'.`
|
|||||||
if runtime.GOOS != "windows" {
|
if runtime.GOOS != "windows" {
|
||||||
successMessage = "🚀 " + successMessage
|
successMessage = "🚀 " + successMessage
|
||||||
}
|
}
|
||||||
// Platform check
|
|
||||||
err = platformCheck()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check we have a cgo capable environment
|
// Chrck for programs and libraries dependencies
|
||||||
logger.Yellow("Checking for prerequisites...")
|
errors, err := cmd.CheckDependencies(logger)
|
||||||
var requiredProgramErrors bool
|
|
||||||
requiredProgramErrors, err = checkRequiredPrograms()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Linux has library deps
|
|
||||||
var libraryErrors bool
|
|
||||||
libraryErrors, err = checkLibraries()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -60,76 +45,14 @@ Create your first project by running 'wails init'.`
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.White("")
|
|
||||||
|
|
||||||
// Check for errors
|
// Check for errors
|
||||||
var errors = libraryErrors || requiredProgramErrors
|
// CheckDependencies() returns !errors
|
||||||
if !errors {
|
// so to get the right message in this
|
||||||
|
// check we have to do it in reversed
|
||||||
|
if errors {
|
||||||
logger.Yellow(successMessage)
|
logger.Yellow(successMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func platformCheck() error {
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "darwin":
|
|
||||||
logger.Yellow("Detected Platform: OSX")
|
|
||||||
case "windows":
|
|
||||||
logger.Yellow("Detected Platform: Windows")
|
|
||||||
case "linux":
|
|
||||||
logger.Yellow("Detected Platform: Linux")
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("Platform %s is currently not supported", runtime.GOOS)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkLibraries() (errors bool, err error) {
|
|
||||||
if runtime.GOOS == "linux" {
|
|
||||||
// Check library prerequisites
|
|
||||||
requiredLibraries, err := cmd.GetRequiredLibraries()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
distroInfo := cmd.GetLinuxDistroInfo()
|
|
||||||
for _, library := range *requiredLibraries {
|
|
||||||
switch distroInfo.Distribution {
|
|
||||||
case cmd.Ubuntu, cmd.Debian:
|
|
||||||
installed, err := cmd.DpkgInstalled(library.Name)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if !installed {
|
|
||||||
errors = true
|
|
||||||
logger.Red("Library '%s' not found. %s", library.Name, library.Help)
|
|
||||||
} else {
|
|
||||||
logger.Green("Library '%s' installed.", library.Name)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return false, cmd.RequestSupportForDistribution(distroInfo, library.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkRequiredPrograms() (errors bool, err error) {
|
|
||||||
requiredPrograms, err := cmd.GetRequiredPrograms()
|
|
||||||
if err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
errors = false
|
|
||||||
programHelper := cmd.NewProgramHelper()
|
|
||||||
for _, program := range *requiredPrograms {
|
|
||||||
bin := programHelper.FindProgram(program.Name)
|
|
||||||
if bin == nil {
|
|
||||||
errors = true
|
|
||||||
logger.Red("Program '%s' not found. %s", program.Name, program.Help)
|
|
||||||
} else {
|
|
||||||
logger.Green("Program '%s' found: %s", program.Name, bin.Path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -72,7 +72,16 @@ func init() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that runtime init.js is the production version
|
||||||
|
err = cmd.InstallProdRuntime(projectDir, projectOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Move to project directory
|
// Move to project directory
|
||||||
err = os.Chdir(projectDir)
|
err = os.Chdir(projectDir)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func init() {
|
|||||||
projectDir := fs.Cwd()
|
projectDir := fs.Cwd()
|
||||||
|
|
||||||
// Install the bridge library
|
// Install the bridge library
|
||||||
err = cmd.InstallBridge("serve", projectDir, projectOptions)
|
err = cmd.InstallBridge(projectDir, projectOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,12 +42,64 @@ To help you in this process, we will ask for some information, add Go/Wails deta
|
|||||||
gomodule = "(Not Set)"
|
gomodule = "(Not Set)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get version numbers for GCC, node & npm
|
||||||
|
program := cmd.NewProgramHelper()
|
||||||
|
// string helpers
|
||||||
|
var gccVersion, nodeVersion, npmVersion string
|
||||||
|
|
||||||
|
// choose between OS (mac,linux,win)
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "darwin":
|
||||||
|
gcc := program.FindProgram("gcc")
|
||||||
|
if gcc != nil {
|
||||||
|
stdout, _, _, _ := gcc.Run("-dumpversion")
|
||||||
|
gccVersion = strings.TrimSpace(stdout)
|
||||||
|
}
|
||||||
|
case "linux":
|
||||||
|
// for linux we have to collect
|
||||||
|
// the distribution name
|
||||||
|
distroInfo := cmd.GetLinuxDistroInfo()
|
||||||
|
linuxDB := cmd.NewLinuxDB()
|
||||||
|
distro := linuxDB.GetDistro(distroInfo.ID)
|
||||||
|
release := distro.GetRelease(distroInfo.Release)
|
||||||
|
gccVersionCommand := release.GccVersionCommand
|
||||||
|
|
||||||
|
gcc := program.FindProgram("gcc")
|
||||||
|
if gcc != nil {
|
||||||
|
stdout, _, _, _ := gcc.Run(gccVersionCommand)
|
||||||
|
gccVersion = strings.TrimSpace(stdout)
|
||||||
|
}
|
||||||
|
case "windows":
|
||||||
|
gcc := program.FindProgram("gcc")
|
||||||
|
if gcc != nil {
|
||||||
|
stdout, _, _, _ := gcc.Run("-dumpversion")
|
||||||
|
gccVersion = strings.TrimSpace(stdout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
npm := program.FindProgram("npm")
|
||||||
|
if npm != nil {
|
||||||
|
stdout, _, _, _ := npm.Run("--version")
|
||||||
|
nodeVersion = stdout
|
||||||
|
nodeVersion = nodeVersion[:len(nodeVersion)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
node := program.FindProgram("node")
|
||||||
|
if node != nil {
|
||||||
|
stdout, _, _, _ := node.Run("--version")
|
||||||
|
npmVersion = stdout
|
||||||
|
npmVersion = npmVersion[:len(npmVersion)-1]
|
||||||
|
}
|
||||||
|
|
||||||
str.WriteString("\n| Name | Value |\n| ----- | ----- |\n")
|
str.WriteString("\n| Name | Value |\n| ----- | ----- |\n")
|
||||||
str.WriteString(fmt.Sprintf("| Wails Version | %s |\n", cmd.Version))
|
str.WriteString(fmt.Sprintf("| Wails Version | %s |\n", cmd.Version))
|
||||||
str.WriteString(fmt.Sprintf("| Go Version | %s |\n", runtime.Version()))
|
str.WriteString(fmt.Sprintf("| Go Version | %s |\n", runtime.Version()))
|
||||||
str.WriteString(fmt.Sprintf("| Platform | %s |\n", runtime.GOOS))
|
str.WriteString(fmt.Sprintf("| Platform | %s |\n", runtime.GOOS))
|
||||||
str.WriteString(fmt.Sprintf("| Arch | %s |\n", runtime.GOARCH))
|
str.WriteString(fmt.Sprintf("| Arch | %s |\n", runtime.GOARCH))
|
||||||
str.WriteString(fmt.Sprintf("| GO111MODULE | %s |\n", gomodule))
|
str.WriteString(fmt.Sprintf("| GO111MODULE | %s |\n", gomodule))
|
||||||
|
str.WriteString(fmt.Sprintf("| GCC | %s |\n", gccVersion))
|
||||||
|
str.WriteString(fmt.Sprintf("| Npm | %s |\n", npmVersion))
|
||||||
|
str.WriteString(fmt.Sprintf("| Node | %s |\n", nodeVersion))
|
||||||
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println("Processing template and preparing for upload.")
|
fmt.Println("Processing template and preparing for upload.")
|
||||||
|
|||||||
110
config.go
Normal file
110
config.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import "github.com/leaanthony/mewn"
|
||||||
|
|
||||||
|
// AppConfig is the configuration structure used when creating a Wails App object
|
||||||
|
type AppConfig struct {
|
||||||
|
Width, Height int
|
||||||
|
Title string
|
||||||
|
defaultHTML string
|
||||||
|
HTML string
|
||||||
|
JS string
|
||||||
|
CSS string
|
||||||
|
Colour string
|
||||||
|
Resizable bool
|
||||||
|
DisableInspector bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWidth returns the desired width
|
||||||
|
func (a *AppConfig) GetWidth() int {
|
||||||
|
return a.Width
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeight returns the desired height
|
||||||
|
func (a *AppConfig) GetHeight() int {
|
||||||
|
return a.Height
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTitle returns the desired window title
|
||||||
|
func (a *AppConfig) GetTitle() string {
|
||||||
|
return a.Title
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultHTML returns the default HTML
|
||||||
|
func (a *AppConfig) GetDefaultHTML() string {
|
||||||
|
return a.defaultHTML
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResizable returns true if the window should be resizable
|
||||||
|
func (a *AppConfig) GetResizable() bool {
|
||||||
|
return a.Resizable
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDisableInspector returns true if the inspector should be disabled
|
||||||
|
func (a *AppConfig) GetDisableInspector() bool {
|
||||||
|
return a.DisableInspector
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetColour returns the colour
|
||||||
|
func (a *AppConfig) GetColour() string {
|
||||||
|
return a.Colour
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCSS returns the user CSS
|
||||||
|
func (a *AppConfig) GetCSS() string {
|
||||||
|
return a.CSS
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetJS returns the user Javascript
|
||||||
|
func (a *AppConfig) GetJS() string {
|
||||||
|
return a.JS
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppConfig) merge(in *AppConfig) error {
|
||||||
|
if in.CSS != "" {
|
||||||
|
a.CSS = in.CSS
|
||||||
|
}
|
||||||
|
if in.Title != "" {
|
||||||
|
a.Title = in.Title
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.Colour != "" {
|
||||||
|
a.Colour = in.Colour
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.JS != "" {
|
||||||
|
a.JS = in.JS
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.Width != 0 {
|
||||||
|
a.Width = in.Width
|
||||||
|
}
|
||||||
|
if in.Height != 0 {
|
||||||
|
a.Height = in.Height
|
||||||
|
}
|
||||||
|
a.Resizable = in.Resizable
|
||||||
|
a.DisableInspector = in.DisableInspector
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates the default configuration
|
||||||
|
func newConfig(userConfig *AppConfig) (*AppConfig, error) {
|
||||||
|
result := &AppConfig{
|
||||||
|
Width: 800,
|
||||||
|
Height: 600,
|
||||||
|
Resizable: true,
|
||||||
|
Title: "My Wails App",
|
||||||
|
Colour: "#FFF", // White by default
|
||||||
|
HTML: mewn.String("./runtime/assets/default.html"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if userConfig != nil {
|
||||||
|
err := result.merge(userConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
7
go.mod
7
go.mod
@@ -1,7 +1,7 @@
|
|||||||
module github.com/wailsapp/wails
|
module github.com/wailsapp/wails
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/semver v1.4.2 // indirect
|
github.com/Masterminds/semver v1.4.2
|
||||||
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc // indirect
|
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc // indirect
|
||||||
github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac
|
github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac
|
||||||
github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947 // indirect
|
github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947 // indirect
|
||||||
@@ -12,9 +12,8 @@ require (
|
|||||||
github.com/kennygrant/sanitize v1.2.4
|
github.com/kennygrant/sanitize v1.2.4
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||||
github.com/leaanthony/mewn v0.10.7
|
github.com/leaanthony/mewn v0.10.7
|
||||||
github.com/leaanthony/slicer v1.3.1
|
github.com/leaanthony/slicer v1.3.2
|
||||||
github.com/leaanthony/spinner v0.5.3
|
github.com/leaanthony/spinner v0.5.3
|
||||||
github.com/masterminds/semver v1.4.2
|
|
||||||
github.com/mattn/go-colorable v0.1.1 // indirect
|
github.com/mattn/go-colorable v0.1.1 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.7 // indirect
|
github.com/mattn/go-isatty v0.0.7 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
@@ -23,9 +22,9 @@ require (
|
|||||||
github.com/pkg/errors v0.8.1 // indirect
|
github.com/pkg/errors v0.8.1 // indirect
|
||||||
github.com/sirupsen/logrus v1.4.1
|
github.com/sirupsen/logrus v1.4.1
|
||||||
github.com/stretchr/testify v1.3.0 // indirect
|
github.com/stretchr/testify v1.3.0 // indirect
|
||||||
github.com/wailsapp/webview v0.2.7
|
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 // indirect
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 // indirect
|
||||||
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 // indirect
|
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 // indirect
|
||||||
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862
|
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862
|
||||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4
|
gopkg.in/AlecAivazis/survey.v1 v1.8.4
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
|
||||||
)
|
)
|
||||||
|
|||||||
18
go.sum
18
go.sum
@@ -25,7 +25,6 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU
|
|||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||||
github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=
|
github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=
|
||||||
github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=
|
github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
@@ -33,22 +32,19 @@ github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
|
|||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/leaanthony/mewn v0.10.7 h1:jCcNJyIUOpwj+I5SuATvCugDjHkoo+j6ubEOxxrxmPA=
|
github.com/leaanthony/mewn v0.10.7 h1:jCcNJyIUOpwj+I5SuATvCugDjHkoo+j6ubEOxxrxmPA=
|
||||||
github.com/leaanthony/mewn v0.10.7/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
|
github.com/leaanthony/mewn v0.10.7/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
|
||||||
github.com/leaanthony/slicer v1.3.1 h1:n2iIV2sxvL/3bpnmVY0vBjXf3yYFWcB6CYLVMrzJxRw=
|
github.com/leaanthony/slicer v1.3.2 h1:kGWWFoyaY5WzwGrUsHXMmGbssuYthP4qYBNlkNpNAB8=
|
||||||
github.com/leaanthony/slicer v1.3.1/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
|
github.com/leaanthony/slicer v1.3.2/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
|
||||||
github.com/leaanthony/spinner v0.5.3 h1:IMTvgdQCec5QA4qRy0wil4XsRP+QcG1OwLWVK/LPZ5Y=
|
github.com/leaanthony/spinner v0.5.3 h1:IMTvgdQCec5QA4qRy0wil4XsRP+QcG1OwLWVK/LPZ5Y=
|
||||||
github.com/leaanthony/spinner v0.5.3/go.mod h1:oHlrvWicr++CVV7ALWYi+qHk/XNA91D9IJ48IqmpVUo=
|
github.com/leaanthony/spinner v0.5.3/go.mod h1:oHlrvWicr++CVV7ALWYi+qHk/XNA91D9IJ48IqmpVUo=
|
||||||
github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8=
|
github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8=
|
||||||
github.com/leaanthony/synx v0.1.0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
|
github.com/leaanthony/synx v0.1.0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
|
||||||
github.com/leaanthony/wincursor v0.1.0 h1:Dsyp68QcF5cCs65AMBmxoYNEm0n8K7mMchG6a8fYxf8=
|
github.com/leaanthony/wincursor v0.1.0 h1:Dsyp68QcF5cCs65AMBmxoYNEm0n8K7mMchG6a8fYxf8=
|
||||||
github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
|
github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
|
||||||
github.com/masterminds/semver v1.4.2 h1:BgrAYDjlAebjtOwS7C/1QZoh5WgyXx4b59ydc+Ph8xI=
|
|
||||||
github.com/masterminds/semver v1.4.2/go.mod h1:s7KNT9fnd7edGzwwP7RBX4H0v/CYd5qdOLfkL1V75yg=
|
|
||||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
|
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
|
||||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
|
||||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
|
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
|
||||||
@@ -73,11 +69,7 @@ github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/wailsapp/webview v0.2.7 h1:fN5L5H9Oivg9IJPk7uaXQnjqB68Fny11ZWkIaTIZHmk=
|
|
||||||
github.com/wailsapp/webview v0.2.7/go.mod h1:XO9HJbKWokDxUYTWQEBCYg95n/To1v7PxvanDNVf8hY=
|
|
||||||
github.com/zserge/webview v0.0.0-20190123072648-16c93bcaeaeb/go.mod h1:a1CV8KR4Dd1eP2g+mEijGOp+HKczwdKHWyx0aPHKvo4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
@@ -86,10 +78,8 @@ golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 h1:6M3SDHlHHDCx2PcQw3S4KsR17
|
|||||||
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb h1:pf3XwC90UUdNPYWZdFjhGBE7DUFuK3Ct1zWmZ65QN30=
|
|
||||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862 h1:rM0ROo5vb9AdYJi1110yjWGMej9ITfKddS89P3Fkhug=
|
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862 h1:rM0ROo5vb9AdYJi1110yjWGMej9ITfKddS89P3Fkhug=
|
||||||
@@ -97,3 +87,7 @@ golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc=
|
gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc=
|
||||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA=
|
gopkg.in/AlecAivazis/survey.v1 v1.8.4/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22 h1:0efs3hwEZhFKsCoP8l6dDB1AZWMgnEl3yWXWRZTOaEA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package wails
|
package binding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type boundFunction struct {
|
type boundFunction struct {
|
||||||
@@ -14,7 +16,7 @@ type boundFunction struct {
|
|||||||
functionType reflect.Type
|
functionType reflect.Type
|
||||||
inputs []reflect.Type
|
inputs []reflect.Type
|
||||||
returnTypes []reflect.Type
|
returnTypes []reflect.Type
|
||||||
log *CustomLogger
|
log *logger.CustomLogger
|
||||||
hasErrorReturnType bool
|
hasErrorReturnType bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +32,7 @@ func newBoundFunction(object interface{}) (*boundFunction, error) {
|
|||||||
fullName: name,
|
fullName: name,
|
||||||
function: objectValue,
|
function: objectValue,
|
||||||
functionType: objectType,
|
functionType: objectType,
|
||||||
log: newCustomLogger(name),
|
log: logger.NewCustomLogger(name),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := result.processParameters()
|
err := result.processParameters()
|
||||||
@@ -55,7 +57,7 @@ func (b *boundFunction) processParameters() error {
|
|||||||
b.inputs[index] = param
|
b.inputs[index] = param
|
||||||
typ := param
|
typ := param
|
||||||
index := index
|
index := index
|
||||||
b.log.DebugFields("Input param", Fields{
|
b.log.DebugFields("Input param", logger.Fields{
|
||||||
"index": index,
|
"index": index,
|
||||||
"name": name,
|
"name": name,
|
||||||
"kind": kind,
|
"kind": kind,
|
||||||
@@ -1,27 +1,33 @@
|
|||||||
package wails
|
package binding
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
import "fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
type internalMethods struct{
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
log *CustomLogger
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
browser *RuntimeBrowser
|
"github.com/wailsapp/wails/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type internalMethods struct {
|
||||||
|
log *logger.CustomLogger
|
||||||
|
browser *runtime.Browser
|
||||||
}
|
}
|
||||||
|
|
||||||
func newInternalMethods() *internalMethods {
|
func newInternalMethods() *internalMethods {
|
||||||
return &internalMethods{
|
return &internalMethods{
|
||||||
log: newCustomLogger("InternalCall"),
|
log: logger.NewCustomLogger("InternalCall"),
|
||||||
browser: newRuntimeBrowser(),
|
browser: runtime.NewBrowser(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *internalMethods) processCall(callData *callData) (interface{}, error) {
|
func (i *internalMethods) processCall(callData *messages.CallData) (interface{}, error) {
|
||||||
if !strings.HasPrefix(callData.BindingName, ".wails.") {
|
if !strings.HasPrefix(callData.BindingName, ".wails.") {
|
||||||
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
|
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip prefix
|
// Strip prefix
|
||||||
var splitCall = strings.Split(callData.BindingName,".")[2:]
|
var splitCall = strings.Split(callData.BindingName, ".")[2:]
|
||||||
if len(splitCall) != 2 {
|
if len(splitCall) != 2 {
|
||||||
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
|
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
|
||||||
}
|
}
|
||||||
@@ -43,7 +49,7 @@ func (i *internalMethods) processBrowserCommand(command string, data interface{}
|
|||||||
if url[0] == '"' {
|
if url[0] == '"' {
|
||||||
url = url[1:]
|
url = url[1:]
|
||||||
}
|
}
|
||||||
if i := len(url)-1; url[i] == '"' {
|
if i := len(url) - 1; url[i] == '"' {
|
||||||
url = url[:i]
|
url = url[:i]
|
||||||
}
|
}
|
||||||
i.log.Debugf("Calling Browser.OpenURL with '%s'", url)
|
i.log.Debugf("Calling Browser.OpenURL with '%s'", url)
|
||||||
@@ -54,7 +60,7 @@ func (i *internalMethods) processBrowserCommand(command string, data interface{}
|
|||||||
if filename[0] == '"' {
|
if filename[0] == '"' {
|
||||||
filename = filename[1:]
|
filename = filename[1:]
|
||||||
}
|
}
|
||||||
if i := len(filename)-1; filename[i] == '"' {
|
if i := len(filename) - 1; filename[i] == '"' {
|
||||||
filename = filename[:i]
|
filename = filename[:i]
|
||||||
}
|
}
|
||||||
i.log.Debugf("Calling Browser.OpenFile with '%s'", filename)
|
i.log.Debugf("Calling Browser.OpenFile with '%s'", filename)
|
||||||
@@ -1,47 +1,46 @@
|
|||||||
package wails
|
package binding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
// Manager handles method binding
|
||||||
|
type Manager struct {
|
||||||
binding:
|
|
||||||
Name() // Full name (package+name)
|
|
||||||
Call(params)
|
|
||||||
|
|
||||||
**/
|
|
||||||
|
|
||||||
type bindingManager struct {
|
|
||||||
methods map[string]*boundMethod
|
methods map[string]*boundMethod
|
||||||
functions map[string]*boundFunction
|
functions map[string]*boundFunction
|
||||||
internalMethods *internalMethods
|
internalMethods *internalMethods
|
||||||
initMethods []*boundMethod
|
initMethods []*boundMethod
|
||||||
log *CustomLogger
|
log *logger.CustomLogger
|
||||||
renderer Renderer
|
renderer interfaces.Renderer
|
||||||
runtime *Runtime // The runtime object to pass to bound structs
|
runtime interfaces.Runtime // The runtime object to pass to bound structs
|
||||||
objectsToBind []interface{}
|
objectsToBind []interface{}
|
||||||
bindPackageNames bool // Package name should be considered when binding
|
bindPackageNames bool // Package name should be considered when binding
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBindingManager() *bindingManager {
|
// NewManager creates a new Manager struct
|
||||||
result := &bindingManager{
|
func NewManager() interfaces.BindingManager {
|
||||||
|
result := &Manager{
|
||||||
methods: make(map[string]*boundMethod),
|
methods: make(map[string]*boundMethod),
|
||||||
functions: make(map[string]*boundFunction),
|
functions: make(map[string]*boundFunction),
|
||||||
log: newCustomLogger("Bind"),
|
log: logger.NewCustomLogger("Bind"),
|
||||||
internalMethods: newInternalMethods(),
|
internalMethods: newInternalMethods(),
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets flag to indicate package names should be considered when binding
|
// BindPackageNames sets a flag to indicate package names should be considered when binding
|
||||||
func (b *bindingManager) BindPackageNames() {
|
func (b *Manager) BindPackageNames() {
|
||||||
b.bindPackageNames = true
|
b.bindPackageNames = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bindingManager) start(renderer Renderer, runtime *Runtime) error {
|
// Start the binding manager
|
||||||
|
func (b *Manager) Start(renderer interfaces.Renderer, runtime interfaces.Runtime) error {
|
||||||
b.log.Info("Starting")
|
b.log.Info("Starting")
|
||||||
b.renderer = renderer
|
b.renderer = renderer
|
||||||
b.runtime = runtime
|
b.runtime = runtime
|
||||||
@@ -54,7 +53,7 @@ func (b *bindingManager) start(renderer Renderer, runtime *Runtime) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bindingManager) initialise() error {
|
func (b *Manager) initialise() error {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
// var binding *boundMethod
|
// var binding *boundMethod
|
||||||
@@ -92,7 +91,7 @@ func (b *bindingManager) initialise() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// bind the given struct method
|
// bind the given struct method
|
||||||
func (b *bindingManager) bindMethod(object interface{}) error {
|
func (b *Manager) bindMethod(object interface{}) error {
|
||||||
|
|
||||||
objectType := reflect.TypeOf(object)
|
objectType := reflect.TypeOf(object)
|
||||||
baseName := objectType.String()
|
baseName := objectType.String()
|
||||||
@@ -142,7 +141,7 @@ func (b *bindingManager) bindMethod(object interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// bind the given function object
|
// bind the given function object
|
||||||
func (b *bindingManager) bindFunction(object interface{}) error {
|
func (b *Manager) bindFunction(object interface{}) error {
|
||||||
|
|
||||||
newFunction, err := newBoundFunction(object)
|
newFunction, err := newBoundFunction(object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -159,18 +158,18 @@ func (b *bindingManager) bindFunction(object interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the given object to be bound at start time
|
// Bind saves the given object to be bound at start time
|
||||||
func (b *bindingManager) bind(object interface{}) {
|
func (b *Manager) Bind(object interface{}) {
|
||||||
// Store binding
|
// Store binding
|
||||||
b.objectsToBind = append(b.objectsToBind, object)
|
b.objectsToBind = append(b.objectsToBind, object)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bindingManager) processInternalCall(callData *callData) (interface{}, error) {
|
func (b *Manager) processInternalCall(callData *messages.CallData) (interface{}, error) {
|
||||||
// Strip prefix
|
// Strip prefix
|
||||||
return b.internalMethods.processCall(callData)
|
return b.internalMethods.processCall(callData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, error) {
|
func (b *Manager) processFunctionCall(callData *messages.CallData) (interface{}, error) {
|
||||||
// Return values
|
// Return values
|
||||||
var result []reflect.Value
|
var result []reflect.Value
|
||||||
var err error
|
var err error
|
||||||
@@ -196,10 +195,14 @@ func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, e
|
|||||||
return nil, errorResult.Interface().(error)
|
return nil, errorResult.Interface().(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// fmt.Printf("result = '%+v'\n", result)
|
||||||
|
if len(result) > 0 {
|
||||||
return result[0].Interface(), nil
|
return result[0].Interface(), nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bindingManager) processMethodCall(callData *callData) (interface{}, error) {
|
func (b *Manager) processMethodCall(callData *messages.CallData) (interface{}, error) {
|
||||||
// Return values
|
// Return values
|
||||||
var result []reflect.Value
|
var result []reflect.Value
|
||||||
var err error
|
var err error
|
||||||
@@ -233,8 +236,8 @@ func (b *bindingManager) processMethodCall(callData *callData) (interface{}, err
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// process an incoming call request
|
// ProcessCall processes the given call request
|
||||||
func (b *bindingManager) processCall(callData *callData) (result interface{}, err error) {
|
func (b *Manager) ProcessCall(callData *messages.CallData) (result interface{}, err error) {
|
||||||
b.log.Debugf("Wanting to call %s", callData.BindingName)
|
b.log.Debugf("Wanting to call %s", callData.BindingName)
|
||||||
|
|
||||||
// Determine if this is function call or method call by the number of
|
// Determine if this is function call or method call by the number of
|
||||||
@@ -272,7 +275,7 @@ func (b *bindingManager) processCall(callData *callData) (result interface{}, er
|
|||||||
|
|
||||||
// callWailsInitMethods calls all of the WailsInit methods that were
|
// callWailsInitMethods calls all of the WailsInit methods that were
|
||||||
// registered with the runtime object
|
// registered with the runtime object
|
||||||
func (b *bindingManager) callWailsInitMethods() error {
|
func (b *Manager) callWailsInitMethods() error {
|
||||||
// Create reflect value for runtime object
|
// Create reflect value for runtime object
|
||||||
runtimeValue := reflect.ValueOf(b.runtime)
|
runtimeValue := reflect.ValueOf(b.runtime)
|
||||||
params := []reflect.Value{runtimeValue}
|
params := []reflect.Value{runtimeValue}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package wails
|
package binding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type boundMethod struct {
|
type boundMethod struct {
|
||||||
@@ -13,7 +15,7 @@ type boundMethod struct {
|
|||||||
method reflect.Value
|
method reflect.Value
|
||||||
inputs []reflect.Type
|
inputs []reflect.Type
|
||||||
returnTypes []reflect.Type
|
returnTypes []reflect.Type
|
||||||
log *CustomLogger
|
log *logger.CustomLogger
|
||||||
hasErrorReturnType bool // Indicates if there is an error return type
|
hasErrorReturnType bool // Indicates if there is an error return type
|
||||||
isWailsInit bool
|
isWailsInit bool
|
||||||
}
|
}
|
||||||
@@ -27,7 +29,7 @@ func newBoundMethod(name string, fullName string, method reflect.Value, objectTy
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup logger
|
// Setup logger
|
||||||
result.log = newCustomLogger(result.fullName)
|
result.log = logger.NewCustomLogger(result.fullName)
|
||||||
|
|
||||||
// Check if Parameters are valid
|
// Check if Parameters are valid
|
||||||
err := result.processParameters()
|
err := result.processParameters()
|
||||||
@@ -57,7 +59,7 @@ func (b *boundMethod) processParameters() error {
|
|||||||
b.inputs[index] = param
|
b.inputs[index] = param
|
||||||
typ := param
|
typ := param
|
||||||
index := index
|
index := index
|
||||||
b.log.DebugFields("Input param", Fields{
|
b.log.DebugFields("Input param", logger.Fields{
|
||||||
"index": index,
|
"index": index,
|
||||||
"name": name,
|
"name": name,
|
||||||
"kind": kind,
|
"kind": kind,
|
||||||
@@ -166,10 +168,10 @@ func (b *boundMethod) setInputValue(index int, typ reflect.Type, val interface{}
|
|||||||
reflect.Map,
|
reflect.Map,
|
||||||
reflect.Ptr,
|
reflect.Ptr,
|
||||||
reflect.Slice:
|
reflect.Slice:
|
||||||
logger.Debug("Converting nil to type")
|
b.log.Debug("Converting nil to type")
|
||||||
result = reflect.ValueOf(val).Convert(typ)
|
result = reflect.ValueOf(val).Convert(typ)
|
||||||
default:
|
default:
|
||||||
logger.Debug("Cannot convert nil to type, returning error")
|
b.log.Debug("Cannot convert nil to type, returning error")
|
||||||
return reflect.Zero(typ), fmt.Errorf("Unable to use null value for parameter %d of method %s", index+1, b.fullName)
|
return reflect.Zero(typ), fmt.Errorf("Unable to use null value for parameter %d of method %s", index+1, b.fullName)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1,31 +1,34 @@
|
|||||||
package wails
|
package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
)
|
)
|
||||||
|
|
||||||
// eventManager handles and processes events
|
// Manager handles and processes events
|
||||||
type eventManager struct {
|
type Manager struct {
|
||||||
incomingEvents chan *eventData
|
incomingEvents chan *messages.EventData
|
||||||
listeners map[string][]*eventListener
|
listeners map[string][]*eventListener
|
||||||
exit bool
|
exit bool
|
||||||
log *CustomLogger
|
log *logger.CustomLogger
|
||||||
renderer Renderer // Messages will be dispatched to the frontend
|
renderer interfaces.Renderer // Messages will be dispatched to the frontend
|
||||||
}
|
}
|
||||||
|
|
||||||
// newEventManager creates a new event manager with a 100 event buffer
|
// NewManager creates a new event manager with a 100 event buffer
|
||||||
func newEventManager() *eventManager {
|
func NewManager() interfaces.EventManager {
|
||||||
return &eventManager{
|
return &Manager{
|
||||||
incomingEvents: make(chan *eventData, 100),
|
incomingEvents: make(chan *messages.EventData, 100),
|
||||||
listeners: make(map[string][]*eventListener),
|
listeners: make(map[string][]*eventListener),
|
||||||
exit: false,
|
exit: false,
|
||||||
log: newCustomLogger("Events"),
|
log: logger.NewCustomLogger("Events"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PushEvent places the given event on to the event queue
|
// PushEvent places the given event on to the event queue
|
||||||
func (e *eventManager) PushEvent(eventData *eventData) {
|
func (e *Manager) PushEvent(eventData *messages.EventData) {
|
||||||
e.incomingEvents <- eventData
|
e.incomingEvents <- eventData
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +43,7 @@ type eventListener struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new event listener from the given callback function
|
// Creates a new event listener from the given callback function
|
||||||
func (e *eventManager) addEventListener(eventName string, callback func(...interface{}), counter int) error {
|
func (e *Manager) addEventListener(eventName string, callback func(...interface{}), counter int) error {
|
||||||
|
|
||||||
// Sanity check inputs
|
// Sanity check inputs
|
||||||
if callback == nil {
|
if callback == nil {
|
||||||
@@ -65,18 +68,19 @@ func (e *eventManager) addEventListener(eventName string, callback func(...inter
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *eventManager) On(eventName string, callback func(...interface{})) {
|
// On adds a listener for the given event
|
||||||
|
func (e *Manager) On(eventName string, callback func(...interface{})) {
|
||||||
// Add a persistent eventListener (counter = 0)
|
// Add a persistent eventListener (counter = 0)
|
||||||
e.addEventListener(eventName, callback, 0)
|
e.addEventListener(eventName, callback, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit broadcasts the given event to the subscribed listeners
|
// Emit broadcasts the given event to the subscribed listeners
|
||||||
func (e *eventManager) Emit(eventName string, optionalData ...interface{}) {
|
func (e *Manager) Emit(eventName string, optionalData ...interface{}) {
|
||||||
e.incomingEvents <- &eventData{Name: eventName, Data: optionalData}
|
e.incomingEvents <- &messages.EventData{Name: eventName, Data: optionalData}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts the event manager's queue processing
|
// Start the event manager's queue processing
|
||||||
func (e *eventManager) start(renderer Renderer) {
|
func (e *Manager) Start(renderer interfaces.Renderer) {
|
||||||
|
|
||||||
e.log.Info("Starting")
|
e.log.Info("Starting")
|
||||||
|
|
||||||
@@ -95,7 +99,7 @@ func (e *eventManager) start(renderer Renderer) {
|
|||||||
// TODO: Listen for application exit
|
// TODO: Listen for application exit
|
||||||
select {
|
select {
|
||||||
case event := <-e.incomingEvents:
|
case event := <-e.incomingEvents:
|
||||||
e.log.DebugFields("Got Event", Fields{
|
e.log.DebugFields("Got Event", logger.Fields{
|
||||||
"data": event.Data,
|
"data": event.Data,
|
||||||
"name": event.Name,
|
"name": event.Name,
|
||||||
})
|
})
|
||||||
@@ -143,6 +147,6 @@ func (e *eventManager) start(renderer Renderer) {
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *eventManager) stop() {
|
func (e *Manager) stop() {
|
||||||
e.exit = true
|
e.exit = true
|
||||||
}
|
}
|
||||||
14
lib/interfaces/appconfig.go
Normal file
14
lib/interfaces/appconfig.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package interfaces
|
||||||
|
|
||||||
|
// AppConfig is the application config interface
|
||||||
|
type AppConfig interface {
|
||||||
|
GetWidth() int
|
||||||
|
GetHeight() int
|
||||||
|
GetTitle() string
|
||||||
|
GetResizable() bool
|
||||||
|
GetDefaultHTML() string
|
||||||
|
GetDisableInspector() bool
|
||||||
|
GetColour() string
|
||||||
|
GetCSS() string
|
||||||
|
GetJS() string
|
||||||
|
}
|
||||||
10
lib/interfaces/bindingmanager.go
Normal file
10
lib/interfaces/bindingmanager.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package interfaces
|
||||||
|
|
||||||
|
import "github.com/wailsapp/wails/lib/messages"
|
||||||
|
|
||||||
|
// BindingManager is the binding manager interface
|
||||||
|
type BindingManager interface {
|
||||||
|
Bind(object interface{})
|
||||||
|
Start(renderer Renderer, runtime Runtime) error
|
||||||
|
ProcessCall(callData *messages.CallData) (result interface{}, err error)
|
||||||
|
}
|
||||||
11
lib/interfaces/eventmanager.go
Normal file
11
lib/interfaces/eventmanager.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package interfaces
|
||||||
|
|
||||||
|
import "github.com/wailsapp/wails/lib/messages"
|
||||||
|
|
||||||
|
// EventManager is the event manager interface
|
||||||
|
type EventManager interface {
|
||||||
|
PushEvent(*messages.EventData)
|
||||||
|
Emit(eventName string, optionalData ...interface{})
|
||||||
|
On(eventName string, callback func(...interface{}))
|
||||||
|
Start(Renderer)
|
||||||
|
}
|
||||||
8
lib/interfaces/ipcmanager.go
Normal file
8
lib/interfaces/ipcmanager.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package interfaces
|
||||||
|
|
||||||
|
// IPCManager is the event manager interface
|
||||||
|
type IPCManager interface {
|
||||||
|
BindRenderer(Renderer)
|
||||||
|
Dispatch(message string)
|
||||||
|
Start(eventManager EventManager, bindingManager BindingManager)
|
||||||
|
}
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
package wails
|
package interfaces
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
|
)
|
||||||
// Renderer is an interface describing a Wails target to render the app to
|
// Renderer is an interface describing a Wails target to render the app to
|
||||||
type Renderer interface {
|
type Renderer interface {
|
||||||
Initialise(*AppConfig, *ipcManager, *eventManager) error
|
Initialise(AppConfig, IPCManager, EventManager) error
|
||||||
Run() error
|
Run() error
|
||||||
|
|
||||||
// Binding
|
// Binding
|
||||||
@@ -10,7 +13,7 @@ type Renderer interface {
|
|||||||
Callback(data string) error
|
Callback(data string) error
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
NotifyEvent(eventData *eventData) error
|
NotifyEvent(eventData *messages.EventData) error
|
||||||
|
|
||||||
// Dialog Runtime
|
// Dialog Runtime
|
||||||
SelectFile() string
|
SelectFile() string
|
||||||
4
lib/interfaces/runtime.go
Normal file
4
lib/interfaces/runtime.go
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
package interfaces
|
||||||
|
|
||||||
|
// Runtime interface
|
||||||
|
type Runtime interface {}
|
||||||
@@ -1,13 +1,10 @@
|
|||||||
package wails
|
package ipc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
|
||||||
|
|
||||||
type callData struct {
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
BindingName string `json:"bindingName"`
|
)
|
||||||
Data string `json:"data,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
messageProcessors["call"] = processCallData
|
messageProcessors["call"] = processCallData
|
||||||
@@ -15,7 +12,7 @@ func init() {
|
|||||||
|
|
||||||
func processCallData(message *ipcMessage) (*ipcMessage, error) {
|
func processCallData(message *ipcMessage) (*ipcMessage, error) {
|
||||||
|
|
||||||
var payload callData
|
var payload messages.CallData
|
||||||
|
|
||||||
// Decode binding call data
|
// Decode binding call data
|
||||||
payloadMap := message.Payload.(map[string]interface{})
|
payloadMap := message.Payload.(map[string]interface{})
|
||||||
@@ -1,13 +1,10 @@
|
|||||||
package wails
|
package ipc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
|
||||||
|
|
||||||
type eventData struct {
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
Name string `json:"name"`
|
)
|
||||||
Data interface{} `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the message handler
|
// Register the message handler
|
||||||
func init() {
|
func init() {
|
||||||
@@ -19,7 +16,7 @@ func processEventData(message *ipcMessage) (*ipcMessage, error) {
|
|||||||
|
|
||||||
// TODO: Is it worth double checking this is actually an event message,
|
// TODO: Is it worth double checking this is actually an event message,
|
||||||
// even though that's done by the caller?
|
// even though that's done by the caller?
|
||||||
var payload eventData
|
var payload messages.EventData
|
||||||
|
|
||||||
// Decode event data
|
// Decode event data
|
||||||
payloadMap := message.Payload.(map[string]interface{})
|
payloadMap := message.Payload.(map[string]interface{})
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
package wails
|
package ipc
|
||||||
|
|
||||||
type logData struct {
|
import "github.com/wailsapp/wails/lib/messages"
|
||||||
Level string `json:"level"`
|
|
||||||
Message string `json:"string"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the message handler
|
// Register the message handler
|
||||||
func init() {
|
func init() {
|
||||||
@@ -13,7 +10,7 @@ func init() {
|
|||||||
// This processes the given log message
|
// This processes the given log message
|
||||||
func processLogData(message *ipcMessage) (*ipcMessage, error) {
|
func processLogData(message *ipcMessage) (*ipcMessage, error) {
|
||||||
|
|
||||||
var payload logData
|
var payload messages.LogData
|
||||||
|
|
||||||
// Decode event data
|
// Decode event data
|
||||||
payloadMap := message.Payload.(map[string]interface{})
|
payloadMap := message.Payload.(map[string]interface{})
|
||||||
@@ -1,35 +1,42 @@
|
|||||||
package wails
|
package ipc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ipcManager struct {
|
// Manager manages the IPC subsystem
|
||||||
renderer Renderer // The renderer
|
type Manager struct {
|
||||||
|
renderer interfaces.Renderer // The renderer
|
||||||
messageQueue chan *ipcMessage
|
messageQueue chan *ipcMessage
|
||||||
// quitChannel chan struct{}
|
// quitChannel chan struct{}
|
||||||
// signals chan os.Signal
|
// signals chan os.Signal
|
||||||
log *CustomLogger
|
log *logger.CustomLogger
|
||||||
eventManager *eventManager
|
eventManager interfaces.EventManager
|
||||||
bindingManager *bindingManager
|
bindingManager interfaces.BindingManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIPCManager() *ipcManager {
|
// NewManager creates a new IPC Manager
|
||||||
result := &ipcManager{
|
func NewManager() interfaces.IPCManager {
|
||||||
|
result := &Manager{
|
||||||
messageQueue: make(chan *ipcMessage, 100),
|
messageQueue: make(chan *ipcMessage, 100),
|
||||||
// quitChannel: make(chan struct{}),
|
// quitChannel: make(chan struct{}),
|
||||||
// signals: make(chan os.Signal, 1),
|
// signals: make(chan os.Signal, 1),
|
||||||
log: newCustomLogger("IPC"),
|
log: logger.NewCustomLogger("IPC"),
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the renderer, returns the dispatch function
|
// BindRenderer sets the renderer, returns the dispatch function
|
||||||
func (i *ipcManager) bindRenderer(renderer Renderer) {
|
func (i *Manager) BindRenderer(renderer interfaces.Renderer) {
|
||||||
i.renderer = renderer
|
i.renderer = renderer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingManager) {
|
// Start the IPC Manager
|
||||||
|
func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager interfaces.BindingManager) {
|
||||||
|
|
||||||
// Store manager references
|
// Store manager references
|
||||||
i.eventManager = eventManager
|
i.eventManager = eventManager
|
||||||
@@ -42,36 +49,36 @@ func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingMa
|
|||||||
for running {
|
for running {
|
||||||
select {
|
select {
|
||||||
case incomingMessage := <-i.messageQueue:
|
case incomingMessage := <-i.messageQueue:
|
||||||
i.log.DebugFields("Processing message", Fields{
|
i.log.DebugFields("Processing message", logger.Fields{
|
||||||
"1D": &incomingMessage,
|
"1D": &incomingMessage,
|
||||||
})
|
})
|
||||||
switch incomingMessage.Type {
|
switch incomingMessage.Type {
|
||||||
case "call":
|
case "call":
|
||||||
callData := incomingMessage.Payload.(*callData)
|
callData := incomingMessage.Payload.(*messages.CallData)
|
||||||
i.log.DebugFields("Processing call", Fields{
|
i.log.DebugFields("Processing call", logger.Fields{
|
||||||
"1D": &incomingMessage,
|
"1D": &incomingMessage,
|
||||||
"bindingName": callData.BindingName,
|
"bindingName": callData.BindingName,
|
||||||
"data": callData.Data,
|
"data": callData.Data,
|
||||||
})
|
})
|
||||||
go func() {
|
go func() {
|
||||||
result, err := bindingManager.processCall(callData)
|
result, err := bindingManager.ProcessCall(callData)
|
||||||
i.log.DebugFields("processed call", Fields{"result": result, "err": err})
|
i.log.DebugFields("processed call", logger.Fields{"result": result, "err": err})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
incomingMessage.ReturnError(err.Error())
|
incomingMessage.ReturnError(err.Error())
|
||||||
} else {
|
} else {
|
||||||
incomingMessage.ReturnSuccess(result)
|
incomingMessage.ReturnSuccess(result)
|
||||||
}
|
}
|
||||||
i.log.DebugFields("Finished processing call", Fields{
|
i.log.DebugFields("Finished processing call", logger.Fields{
|
||||||
"1D": &incomingMessage,
|
"1D": &incomingMessage,
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
case "event":
|
case "event":
|
||||||
|
|
||||||
// Extract event data
|
// Extract event data
|
||||||
eventData := incomingMessage.Payload.(*eventData)
|
eventData := incomingMessage.Payload.(*messages.EventData)
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
i.log.DebugFields("Processing event", Fields{
|
i.log.DebugFields("Processing event", logger.Fields{
|
||||||
"name": eventData.Name,
|
"name": eventData.Name,
|
||||||
"data": eventData.Data,
|
"data": eventData.Data,
|
||||||
})
|
})
|
||||||
@@ -80,24 +87,24 @@ func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingMa
|
|||||||
i.eventManager.PushEvent(eventData)
|
i.eventManager.PushEvent(eventData)
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
i.log.DebugFields("Finished processing event", Fields{
|
i.log.DebugFields("Finished processing event", logger.Fields{
|
||||||
"name": eventData.Name,
|
"name": eventData.Name,
|
||||||
})
|
})
|
||||||
case "log":
|
case "log":
|
||||||
logdata := incomingMessage.Payload.(*logData)
|
logdata := incomingMessage.Payload.(*messages.LogData)
|
||||||
switch logdata.Level {
|
switch logdata.Level {
|
||||||
case "info":
|
case "info":
|
||||||
logger.Info(logdata.Message)
|
logger.GlobalLogger.Info(logdata.Message)
|
||||||
case "debug":
|
case "debug":
|
||||||
logger.Debug(logdata.Message)
|
logger.GlobalLogger.Debug(logdata.Message)
|
||||||
case "warning":
|
case "warning":
|
||||||
logger.Warning(logdata.Message)
|
logger.GlobalLogger.Warn(logdata.Message)
|
||||||
case "error":
|
case "error":
|
||||||
logger.Error(logdata.Message)
|
logger.GlobalLogger.Error(logdata.Message)
|
||||||
case "fatal":
|
case "fatal":
|
||||||
logger.Fatal(logdata.Message)
|
logger.GlobalLogger.Fatal(logdata.Message)
|
||||||
default:
|
default:
|
||||||
i.log.ErrorFields("Invalid log level sent", Fields{
|
logger.ErrorFields("Invalid log level sent", logger.Fields{
|
||||||
"level": logdata.Level,
|
"level": logdata.Level,
|
||||||
"message": logdata.Message,
|
"message": logdata.Message,
|
||||||
})
|
})
|
||||||
@@ -107,7 +114,7 @@ func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingMa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
i.log.DebugFields("Finished processing message", Fields{
|
i.log.DebugFields("Finished processing message", logger.Fields{
|
||||||
"1D": &incomingMessage,
|
"1D": &incomingMessage,
|
||||||
})
|
})
|
||||||
// case <-manager.quitChannel:
|
// case <-manager.quitChannel:
|
||||||
@@ -125,7 +132,7 @@ func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingMa
|
|||||||
// Dispatch receives JSON encoded messages from the renderer.
|
// Dispatch receives JSON encoded messages from the renderer.
|
||||||
// It processes the message to ensure that it is valid and places
|
// It processes the message to ensure that it is valid and places
|
||||||
// the processed message on the message queue
|
// the processed message on the message queue
|
||||||
func (i *ipcManager) Dispatch(message string) {
|
func (i *Manager) Dispatch(message string) {
|
||||||
|
|
||||||
// Create a new IPC Message
|
// Create a new IPC Message
|
||||||
incomingMessage, err := newIPCMessage(message, i.SendResponse)
|
incomingMessage, err := newIPCMessage(message, i.SendResponse)
|
||||||
@@ -148,7 +155,7 @@ func (i *ipcManager) Dispatch(message string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SendResponse sends the given response back to the frontend
|
// SendResponse sends the given response back to the frontend
|
||||||
func (i *ipcManager) SendResponse(response *ipcResponse) error {
|
func (i *Manager) SendResponse(response *ipcResponse) error {
|
||||||
|
|
||||||
// Serialise the Message
|
// Serialise the Message
|
||||||
data, err := response.Serialise()
|
data, err := response.Serialise()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package wails
|
package ipc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package wails
|
package ipc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package wails
|
package logger
|
||||||
|
|
||||||
// CustomLogger is a wrapper object to logrus
|
// CustomLogger is a wrapper object to logrus
|
||||||
type CustomLogger struct {
|
type CustomLogger struct {
|
||||||
@@ -6,7 +6,8 @@ type CustomLogger struct {
|
|||||||
errorOnly bool
|
errorOnly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCustomLogger(prefix string) *CustomLogger {
|
// NewCustomLogger creates a new custom logger with the given prefix
|
||||||
|
func NewCustomLogger(prefix string) *CustomLogger {
|
||||||
return &CustomLogger{
|
return &CustomLogger{
|
||||||
prefix: "[" + prefix + "] ",
|
prefix: "[" + prefix + "] ",
|
||||||
}
|
}
|
||||||
@@ -14,90 +15,90 @@ func newCustomLogger(prefix string) *CustomLogger {
|
|||||||
|
|
||||||
// Info level message
|
// Info level message
|
||||||
func (c *CustomLogger) Info(message string) {
|
func (c *CustomLogger) Info(message string) {
|
||||||
logger.Info(c.prefix + message)
|
GlobalLogger.Info(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Infof - formatted message
|
// Infof - formatted message
|
||||||
func (c *CustomLogger) Infof(message string, args ...interface{}) {
|
func (c *CustomLogger) Infof(message string, args ...interface{}) {
|
||||||
logger.Infof(c.prefix+message, args...)
|
GlobalLogger.Infof(c.prefix+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InfoFields - message with fields
|
// InfoFields - message with fields
|
||||||
func (c *CustomLogger) InfoFields(message string, fields Fields) {
|
func (c *CustomLogger) InfoFields(message string, fields Fields) {
|
||||||
logger.WithFields(map[string]interface{}(fields)).Info(c.prefix + message)
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Info(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug level message
|
// Debug level message
|
||||||
func (c *CustomLogger) Debug(message string) {
|
func (c *CustomLogger) Debug(message string) {
|
||||||
logger.Debug(c.prefix + message)
|
GlobalLogger.Debug(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debugf - formatted message
|
// Debugf - formatted message
|
||||||
func (c *CustomLogger) Debugf(message string, args ...interface{}) {
|
func (c *CustomLogger) Debugf(message string, args ...interface{}) {
|
||||||
logger.Debugf(c.prefix+message, args...)
|
GlobalLogger.Debugf(c.prefix+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DebugFields - message with fields
|
// DebugFields - message with fields
|
||||||
func (c *CustomLogger) DebugFields(message string, fields Fields) {
|
func (c *CustomLogger) DebugFields(message string, fields Fields) {
|
||||||
logger.WithFields(map[string]interface{}(fields)).Debug(c.prefix + message)
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Debug(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warn level message
|
// Warn level message
|
||||||
func (c *CustomLogger) Warn(message string) {
|
func (c *CustomLogger) Warn(message string) {
|
||||||
logger.Warn(c.prefix + message)
|
GlobalLogger.Warn(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warnf - formatted message
|
// Warnf - formatted message
|
||||||
func (c *CustomLogger) Warnf(message string, args ...interface{}) {
|
func (c *CustomLogger) Warnf(message string, args ...interface{}) {
|
||||||
logger.Warnf(c.prefix+message, args...)
|
GlobalLogger.Warnf(c.prefix+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WarnFields - message with fields
|
// WarnFields - message with fields
|
||||||
func (c *CustomLogger) WarnFields(message string, fields Fields) {
|
func (c *CustomLogger) WarnFields(message string, fields Fields) {
|
||||||
logger.WithFields(map[string]interface{}(fields)).Warn(c.prefix + message)
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Warn(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error level message
|
// Error level message
|
||||||
func (c *CustomLogger) Error(message string) {
|
func (c *CustomLogger) Error(message string) {
|
||||||
logger.Error(c.prefix + message)
|
GlobalLogger.Error(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errorf - formatted message
|
// Errorf - formatted message
|
||||||
func (c *CustomLogger) Errorf(message string, args ...interface{}) {
|
func (c *CustomLogger) Errorf(message string, args ...interface{}) {
|
||||||
logger.Errorf(c.prefix+message, args...)
|
GlobalLogger.Errorf(c.prefix+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrorFields - message with fields
|
// ErrorFields - message with fields
|
||||||
func (c *CustomLogger) ErrorFields(message string, fields Fields) {
|
func (c *CustomLogger) ErrorFields(message string, fields Fields) {
|
||||||
logger.WithFields(map[string]interface{}(fields)).Error(c.prefix + message)
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Error(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal level message
|
// Fatal level message
|
||||||
func (c *CustomLogger) Fatal(message string) {
|
func (c *CustomLogger) Fatal(message string) {
|
||||||
logger.Fatal(c.prefix + message)
|
GlobalLogger.Fatal(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf - formatted message
|
// Fatalf - formatted message
|
||||||
func (c *CustomLogger) Fatalf(message string, args ...interface{}) {
|
func (c *CustomLogger) Fatalf(message string, args ...interface{}) {
|
||||||
logger.Fatalf(c.prefix+message, args...)
|
GlobalLogger.Fatalf(c.prefix+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FatalFields - message with fields
|
// FatalFields - message with fields
|
||||||
func (c *CustomLogger) FatalFields(message string, fields Fields) {
|
func (c *CustomLogger) FatalFields(message string, fields Fields) {
|
||||||
logger.WithFields(map[string]interface{}(fields)).Fatal(c.prefix + message)
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Fatal(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panic level message
|
// Panic level message
|
||||||
func (c *CustomLogger) Panic(message string) {
|
func (c *CustomLogger) Panic(message string) {
|
||||||
logger.Panic(c.prefix + message)
|
GlobalLogger.Panic(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panicf - formatted message
|
// Panicf - formatted message
|
||||||
func (c *CustomLogger) Panicf(message string, args ...interface{}) {
|
func (c *CustomLogger) Panicf(message string, args ...interface{}) {
|
||||||
logger.Panicf(c.prefix+message, args...)
|
GlobalLogger.Panicf(c.prefix+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PanicFields - message with fields
|
// PanicFields - message with fields
|
||||||
func (c *CustomLogger) PanicFields(message string, fields Fields) {
|
func (c *CustomLogger) PanicFields(message string, fields Fields) {
|
||||||
logger.WithFields(map[string]interface{}(fields)).Panic(c.prefix + message)
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Panic(c.prefix + message)
|
||||||
}
|
}
|
||||||
47
lib/logger/log.go
Normal file
47
lib/logger/log.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GlobalLogger is the global logger
|
||||||
|
var GlobalLogger = logrus.New()
|
||||||
|
|
||||||
|
// Fields is used by the customLogger object to output
|
||||||
|
// fields along with a message
|
||||||
|
type Fields map[string]interface{}
|
||||||
|
|
||||||
|
// Default options for the global logger
|
||||||
|
func init() {
|
||||||
|
GlobalLogger.SetOutput(os.Stdout)
|
||||||
|
GlobalLogger.SetLevel(logrus.DebugLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorFields is a helper for logging fields to the global logger
|
||||||
|
func ErrorFields(message string, fields Fields) {
|
||||||
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogLevel sets the log level to the given level
|
||||||
|
func SetLogLevel(level string) {
|
||||||
|
switch strings.ToLower(level) {
|
||||||
|
case "info":
|
||||||
|
GlobalLogger.SetLevel(logrus.InfoLevel)
|
||||||
|
case "debug":
|
||||||
|
GlobalLogger.SetLevel(logrus.DebugLevel)
|
||||||
|
case "warn":
|
||||||
|
GlobalLogger.SetLevel(logrus.WarnLevel)
|
||||||
|
case "error":
|
||||||
|
GlobalLogger.SetLevel(logrus.ErrorLevel)
|
||||||
|
case "fatal":
|
||||||
|
GlobalLogger.SetLevel(logrus.FatalLevel)
|
||||||
|
case "panic":
|
||||||
|
GlobalLogger.SetLevel(logrus.PanicLevel)
|
||||||
|
default:
|
||||||
|
GlobalLogger.SetLevel(logrus.DebugLevel)
|
||||||
|
GlobalLogger.Warnf("Log level '%s' not recognised. Setting to Debug.", level)
|
||||||
|
}
|
||||||
|
}
|
||||||
7
lib/messages/calldata.go
Normal file
7
lib/messages/calldata.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
// CallData represents a call to a Go function/method
|
||||||
|
type CallData struct {
|
||||||
|
BindingName string `json:"bindingName"`
|
||||||
|
Data string `json:"data,omitempty"`
|
||||||
|
}
|
||||||
7
lib/messages/eventdata.go
Normal file
7
lib/messages/eventdata.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
// EventData represents an event sent from the frontend
|
||||||
|
type EventData struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
7
lib/messages/logdata.go
Normal file
7
lib/messages/logdata.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
// LogData represents a call to log from the frontend
|
||||||
|
type LogData struct {
|
||||||
|
Level string `json:"level"`
|
||||||
|
Message string `json:"string"`
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package wails
|
package renderer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -10,6 +10,9 @@ import (
|
|||||||
"github.com/dchest/htmlmin"
|
"github.com/dchest/htmlmin"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/leaanthony/mewn"
|
"github.com/leaanthony/mewn"
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
)
|
)
|
||||||
|
|
||||||
type messageType int
|
type messageType int
|
||||||
@@ -28,17 +31,17 @@ func (m messageType) toString() string {
|
|||||||
return [...]string{"j", "s", "h", "n", "b", "c", "w"}[m]
|
return [...]string{"j", "s", "h", "n", "b", "c", "w"}[m]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Headless is a backend that opens a local web server
|
// Bridge is a backend that opens a local web server
|
||||||
// and renders the files over a websocket
|
// and renders the files over a websocket
|
||||||
type Headless struct {
|
type Bridge struct {
|
||||||
// Common
|
// Common
|
||||||
log *CustomLogger
|
log *logger.CustomLogger
|
||||||
ipcManager *ipcManager
|
ipcManager interfaces.IPCManager
|
||||||
appConfig *AppConfig
|
appConfig interfaces.AppConfig
|
||||||
eventManager *eventManager
|
eventManager interfaces.EventManager
|
||||||
bindingCache []string
|
bindingCache []string
|
||||||
|
|
||||||
// Headless specific
|
// Bridge specific
|
||||||
initialisationJS []string
|
initialisationJS []string
|
||||||
server *http.Server
|
server *http.Server
|
||||||
theConnection *websocket.Conn
|
theConnection *websocket.Conn
|
||||||
@@ -47,17 +50,17 @@ type Headless struct {
|
|||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise the Headless Renderer
|
// Initialise the Bridge Renderer
|
||||||
func (h *Headless) Initialise(appConfig *AppConfig, ipcManager *ipcManager, eventManager *eventManager) error {
|
func (h *Bridge) Initialise(appConfig interfaces.AppConfig, ipcManager interfaces.IPCManager, eventManager interfaces.EventManager) error {
|
||||||
h.ipcManager = ipcManager
|
h.ipcManager = ipcManager
|
||||||
h.appConfig = appConfig
|
h.appConfig = appConfig
|
||||||
h.eventManager = eventManager
|
h.eventManager = eventManager
|
||||||
ipcManager.bindRenderer(h)
|
ipcManager.BindRenderer(h)
|
||||||
h.log = newCustomLogger("Bridge")
|
h.log = logger.NewCustomLogger("Bridge")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headless) evalJS(js string, mtype messageType) error {
|
func (h *Bridge) evalJS(js string, mtype messageType) error {
|
||||||
|
|
||||||
message := mtype.toString() + js
|
message := mtype.toString() + js
|
||||||
|
|
||||||
@@ -71,7 +74,7 @@ func (h *Headless) evalJS(js string, mtype messageType) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headless) injectCSS(css string) {
|
func (h *Bridge) injectCSS(css string) {
|
||||||
// Minify css to overcome issues in the browser with carriage returns
|
// Minify css to overcome issues in the browser with carriage returns
|
||||||
minified, err := htmlmin.Minify([]byte(css), &htmlmin.Options{
|
minified, err := htmlmin.Minify([]byte(css), &htmlmin.Options{
|
||||||
MinifyStyles: true,
|
MinifyStyles: true,
|
||||||
@@ -83,11 +86,11 @@ func (h *Headless) injectCSS(css string) {
|
|||||||
minifiedCSS = strings.Replace(minifiedCSS, "\\", "\\\\", -1)
|
minifiedCSS = strings.Replace(minifiedCSS, "\\", "\\\\", -1)
|
||||||
minifiedCSS = strings.Replace(minifiedCSS, "'", "\\'", -1)
|
minifiedCSS = strings.Replace(minifiedCSS, "'", "\\'", -1)
|
||||||
minifiedCSS = strings.Replace(minifiedCSS, "\n", " ", -1)
|
minifiedCSS = strings.Replace(minifiedCSS, "\n", " ", -1)
|
||||||
inject := fmt.Sprintf("wails._.injectCSS('%s')", minifiedCSS)
|
inject := fmt.Sprintf("wails._.InjectCSS('%s')", minifiedCSS)
|
||||||
h.evalJS(inject, cssMessage)
|
h.evalJS(inject, cssMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headless) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *Bridge) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024)
|
conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
|
http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
|
||||||
@@ -102,7 +105,7 @@ func (h *Headless) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
go h.start(conn)
|
go h.start(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headless) sendMessage(conn *websocket.Conn, msg string) {
|
func (h *Bridge) sendMessage(conn *websocket.Conn, msg string) {
|
||||||
|
|
||||||
h.lock.Lock()
|
h.lock.Lock()
|
||||||
defer h.lock.Unlock()
|
defer h.lock.Unlock()
|
||||||
@@ -112,12 +115,12 @@ func (h *Headless) sendMessage(conn *websocket.Conn, msg string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headless) start(conn *websocket.Conn) {
|
func (h *Bridge) start(conn *websocket.Conn) {
|
||||||
|
|
||||||
// set external.invoke
|
// set external.invoke
|
||||||
h.log.Infof("Connected to frontend.")
|
h.log.Infof("Connected to frontend.")
|
||||||
|
|
||||||
wailsRuntime := mewn.String("./wailsruntimeassets/default/wails.min.js")
|
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
||||||
h.evalJS(wailsRuntime, wailsRuntimeMessage)
|
h.evalJS(wailsRuntime, wailsRuntimeMessage)
|
||||||
|
|
||||||
// Inject bindings
|
// Inject bindings
|
||||||
@@ -144,8 +147,8 @@ func (h *Headless) start(conn *websocket.Conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the app in headless mode!
|
// Run the app in Bridge mode!
|
||||||
func (h *Headless) Run() error {
|
func (h *Bridge) Run() error {
|
||||||
h.server = &http.Server{Addr: ":34115"}
|
h.server = &http.Server{Addr: ":34115"}
|
||||||
http.HandleFunc("/bridge", h.wsBridgeHandler)
|
http.HandleFunc("/bridge", h.wsBridgeHandler)
|
||||||
|
|
||||||
@@ -160,45 +163,45 @@ func (h *Headless) Run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewBinding creates a new binding with the frontend
|
// NewBinding creates a new binding with the frontend
|
||||||
func (h *Headless) NewBinding(methodName string) error {
|
func (h *Bridge) NewBinding(methodName string) error {
|
||||||
h.bindingCache = append(h.bindingCache, methodName)
|
h.bindingCache = append(h.bindingCache, methodName)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectFile is unsupported for Headless but required
|
// SelectFile is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) SelectFile() string {
|
func (h *Bridge) SelectFile() string {
|
||||||
h.log.Warn("SelectFile() unsupported in bridge mode")
|
h.log.Warn("SelectFile() unsupported in bridge mode")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectDirectory is unsupported for Headless but required
|
// SelectDirectory is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) SelectDirectory() string {
|
func (h *Bridge) SelectDirectory() string {
|
||||||
h.log.Warn("SelectDirectory() unsupported in bridge mode")
|
h.log.Warn("SelectDirectory() unsupported in bridge mode")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectSaveFile is unsupported for Headless but required
|
// SelectSaveFile is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) SelectSaveFile() string {
|
func (h *Bridge) SelectSaveFile() string {
|
||||||
h.log.Warn("SelectSaveFile() unsupported in bridge mode")
|
h.log.Warn("SelectSaveFile() unsupported in bridge mode")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback sends a callback to the frontend
|
// Callback sends a callback to the frontend
|
||||||
func (h *Headless) Callback(data string) error {
|
func (h *Bridge) Callback(data string) error {
|
||||||
return h.evalJS(data, callbackMessage)
|
return h.evalJS(data, callbackMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyEvent notifies the frontend of an event
|
// NotifyEvent notifies the frontend of an event
|
||||||
func (h *Headless) NotifyEvent(event *eventData) error {
|
func (h *Bridge) NotifyEvent(event *messages.EventData) error {
|
||||||
|
|
||||||
// Look out! Nils about!
|
// Look out! Nils about!
|
||||||
var err error
|
var err error
|
||||||
if event == nil {
|
if event == nil {
|
||||||
err = fmt.Errorf("Sent nil event to renderer.webViewRenderer")
|
err = fmt.Errorf("Sent nil event to renderer.webViewRenderer")
|
||||||
logger.Error(err)
|
h.log.Error(err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,37 +218,37 @@ func (h *Headless) NotifyEvent(event *eventData) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message := fmt.Sprintf("window.wails._.notify('%s','%s')", event.Name, data)
|
message := fmt.Sprintf("window.wails._.Notify('%s','%s')", event.Name, data)
|
||||||
return h.evalJS(message, notifyMessage)
|
return h.evalJS(message, notifyMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetColour is unsupported for Headless but required
|
// SetColour is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) SetColour(colour string) error {
|
func (h *Bridge) SetColour(colour string) error {
|
||||||
h.log.WarnFields("SetColour ignored for headless more", Fields{"col": colour})
|
h.log.WarnFields("SetColour ignored for Bridge more", logger.Fields{"col": colour})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fullscreen is unsupported for Headless but required
|
// Fullscreen is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) Fullscreen() {
|
func (h *Bridge) Fullscreen() {
|
||||||
h.log.Warn("Fullscreen() unsupported in bridge mode")
|
h.log.Warn("Fullscreen() unsupported in bridge mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnFullscreen is unsupported for Headless but required
|
// UnFullscreen is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) UnFullscreen() {
|
func (h *Bridge) UnFullscreen() {
|
||||||
h.log.Warn("UnFullscreen() unsupported in bridge mode")
|
h.log.Warn("UnFullscreen() unsupported in bridge mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTitle is currently unsupported for Headless but required
|
// SetTitle is currently unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) SetTitle(title string) {
|
func (h *Bridge) SetTitle(title string) {
|
||||||
h.log.WarnFields("SetTitle() unsupported in bridge mode", Fields{"title": title})
|
h.log.WarnFields("SetTitle() unsupported in bridge mode", logger.Fields{"title": title})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close is unsupported for Headless but required
|
// Close is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) Close() {
|
func (h *Bridge) Close() {
|
||||||
h.log.Warn("Close() unsupported in bridge mode")
|
h.log.Warn("Close() unsupported in bridge mode")
|
||||||
}
|
}
|
||||||
10
lib/renderer/renderer-mewn.go
Normal file
10
lib/renderer/renderer-mewn.go
Normal file
File diff suppressed because one or more lines are too long
@@ -1,53 +1,62 @@
|
|||||||
package wails
|
package renderer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-playground/colors"
|
"github.com/go-playground/colors"
|
||||||
"github.com/leaanthony/mewn"
|
"github.com/leaanthony/mewn"
|
||||||
"github.com/wailsapp/webview"
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
|
wv "github.com/wailsapp/wails/lib/renderer/webview"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Window defines the main application window
|
// WebView defines the main webview application window
|
||||||
// Default values in []
|
// Default values in []
|
||||||
type webViewRenderer struct {
|
type WebView struct {
|
||||||
window webview.WebView // The webview object
|
window wv.WebView // The webview object
|
||||||
ipc *ipcManager
|
ipc interfaces.IPCManager
|
||||||
log *CustomLogger
|
log *logger.CustomLogger
|
||||||
config *AppConfig
|
config interfaces.AppConfig
|
||||||
eventManager *eventManager
|
eventManager interfaces.EventManager
|
||||||
bindingCache []string
|
bindingCache []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewWebView returns a new WebView struct
|
||||||
|
func NewWebView() *WebView {
|
||||||
|
return &WebView{}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialise sets up the WebView
|
// Initialise sets up the WebView
|
||||||
func (w *webViewRenderer) Initialise(config *AppConfig, ipc *ipcManager, eventManager *eventManager) error {
|
func (w *WebView) Initialise(config interfaces.AppConfig, ipc interfaces.IPCManager, eventManager interfaces.EventManager) error {
|
||||||
|
|
||||||
// Store reference to eventManager
|
// Store reference to eventManager
|
||||||
w.eventManager = eventManager
|
w.eventManager = eventManager
|
||||||
|
|
||||||
// Set up logger
|
// Set up logger
|
||||||
w.log = newCustomLogger("WebView")
|
w.log = logger.NewCustomLogger("WebView")
|
||||||
|
|
||||||
// Set up the dispatcher function
|
// Set up the dispatcher function
|
||||||
w.ipc = ipc
|
w.ipc = ipc
|
||||||
ipc.bindRenderer(w)
|
ipc.BindRenderer(w)
|
||||||
|
|
||||||
// Save the config
|
// Save the config
|
||||||
w.config = config
|
w.config = config
|
||||||
|
|
||||||
// Create the WebView instance
|
// Create the WebView instance
|
||||||
w.window = webview.NewWebview(webview.Settings{
|
w.window = wv.NewWebview(wv.Settings{
|
||||||
Width: config.Width,
|
Width: config.GetWidth(),
|
||||||
Height: config.Height,
|
Height: config.GetHeight(),
|
||||||
Title: config.Title,
|
Title: config.GetTitle(),
|
||||||
Resizable: config.Resizable,
|
Resizable: config.GetResizable(),
|
||||||
URL: config.defaultHTML,
|
URL: config.GetDefaultHTML(),
|
||||||
Debug: !config.DisableInspector,
|
Debug: !config.GetDisableInspector(),
|
||||||
ExternalInvokeCallback: func(_ webview.WebView, message string) {
|
ExternalInvokeCallback: func(_ wv.WebView, message string) {
|
||||||
w.ipc.Dispatch(message)
|
w.ipc.Dispatch(message)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -55,7 +64,7 @@ func (w *webViewRenderer) Initialise(config *AppConfig, ipc *ipcManager, eventMa
|
|||||||
// SignalManager.OnExit(w.Exit)
|
// SignalManager.OnExit(w.Exit)
|
||||||
|
|
||||||
// Set colour
|
// Set colour
|
||||||
err := w.SetColour(config.Colour)
|
err := w.SetColour(config.GetColour())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -64,7 +73,8 @@ func (w *webViewRenderer) Initialise(config *AppConfig, ipc *ipcManager, eventMa
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) SetColour(colour string) error {
|
// SetColour sets the window colour
|
||||||
|
func (w *WebView) SetColour(colour string) error {
|
||||||
color, err := colors.Parse(colour)
|
color, err := colors.Parse(colour)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -80,12 +90,12 @@ func (w *webViewRenderer) SetColour(colour string) error {
|
|||||||
|
|
||||||
// evalJS evaluates the given js in the WebView
|
// evalJS evaluates the given js in the WebView
|
||||||
// I should rename this to evilJS lol
|
// I should rename this to evilJS lol
|
||||||
func (w *webViewRenderer) evalJS(js string) error {
|
func (w *WebView) evalJS(js string) error {
|
||||||
outputJS := fmt.Sprintf("%.45s", js)
|
outputJS := fmt.Sprintf("%.45s", js)
|
||||||
if len(js) > 45 {
|
if len(js) > 45 {
|
||||||
outputJS += "..."
|
outputJS += "..."
|
||||||
}
|
}
|
||||||
w.log.DebugFields("Eval", Fields{"js": outputJS})
|
w.log.DebugFields("Eval", logger.Fields{"js": outputJS})
|
||||||
//
|
//
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
w.window.Eval(js)
|
w.window.Eval(js)
|
||||||
@@ -93,12 +103,21 @@ func (w *webViewRenderer) evalJS(js string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Escape the Javascripts!
|
||||||
|
func escapeJS(js string) (string, error) {
|
||||||
|
result := strings.Replace(js, "\\", "\\\\", -1)
|
||||||
|
result = strings.Replace(result, "'", "\\'", -1)
|
||||||
|
result = strings.Replace(result, "\n", "\\n", -1)
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// evalJSSync evaluates the given js in the WebView synchronously
|
// evalJSSync evaluates the given js in the WebView synchronously
|
||||||
// Do not call this from the main thread or you'll nuke your app because
|
// Do not call this from the main thread or you'll nuke your app because
|
||||||
// you won't get the callback.
|
// you won't get the callback.
|
||||||
func (w *webViewRenderer) evalJSSync(js string) error {
|
func (w *WebView) evalJSSync(js string) error {
|
||||||
|
|
||||||
minified, err := escapeJS(js)
|
minified, err := escapeJS(js)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -107,7 +126,7 @@ func (w *webViewRenderer) evalJSSync(js string) error {
|
|||||||
if len(js) > 45 {
|
if len(js) > 45 {
|
||||||
outputJS += "..."
|
outputJS += "..."
|
||||||
}
|
}
|
||||||
w.log.DebugFields("EvalSync", Fields{"js": outputJS})
|
w.log.DebugFields("EvalSync", logger.Fields{"js": outputJS})
|
||||||
|
|
||||||
ID := fmt.Sprintf("syncjs:%d:%d", time.Now().Unix(), rand.Intn(9999))
|
ID := fmt.Sprintf("syncjs:%d:%d", time.Now().Unix(), rand.Intn(9999))
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
@@ -122,7 +141,7 @@ func (w *webViewRenderer) evalJSSync(js string) error {
|
|||||||
wg.Done()
|
wg.Done()
|
||||||
exit = true
|
exit = true
|
||||||
})
|
})
|
||||||
command := fmt.Sprintf("wails._.addScript('%s', '%s')", minified, ID)
|
command := fmt.Sprintf("wails._.AddScript('%s', '%s')", minified, ID)
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
w.window.Eval(command)
|
w.window.Eval(command)
|
||||||
})
|
})
|
||||||
@@ -137,26 +156,30 @@ func (w *webViewRenderer) evalJSSync(js string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// injectCSS adds the given CSS to the WebView
|
// injectCSS adds the given CSS to the WebView
|
||||||
func (w *webViewRenderer) injectCSS(css string) {
|
func (w *WebView) injectCSS(css string) {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
w.window.InjectCSS(css)
|
w.window.InjectCSS(css)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quit the window
|
// Exit closes the window
|
||||||
func (w *webViewRenderer) Exit() {
|
func (w *WebView) Exit() {
|
||||||
w.window.Exit()
|
w.window.Exit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the window main loop
|
// Run the window main loop
|
||||||
func (w *webViewRenderer) Run() error {
|
func (w *WebView) Run() error {
|
||||||
|
|
||||||
w.log.Info("Run()")
|
w.log.Info("Run()")
|
||||||
|
|
||||||
// Runtime assets
|
// Runtime assets
|
||||||
wailsRuntime := mewn.String("./wailsruntimeassets/default/wails.min.js")
|
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
||||||
|
w.log.Info("1")
|
||||||
|
|
||||||
w.evalJS(wailsRuntime)
|
w.evalJS(wailsRuntime)
|
||||||
|
|
||||||
|
w.log.Info("2")
|
||||||
|
|
||||||
// Ping the wait channel when the wails runtime is loaded
|
// Ping the wait channel when the wails runtime is loaded
|
||||||
w.eventManager.On("wails:loaded", func(...interface{}) {
|
w.eventManager.On("wails:loaded", func(...interface{}) {
|
||||||
|
|
||||||
@@ -168,38 +191,30 @@ func (w *webViewRenderer) Run() error {
|
|||||||
w.evalJSSync(binding)
|
w.evalJSSync(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Inject Framework
|
|
||||||
// if w.frameworkJS != "" {
|
|
||||||
// w.evalJSSync(w.frameworkJS)
|
|
||||||
// }
|
|
||||||
// if w.frameworkCSS != "" {
|
|
||||||
// w.injectCSS(w.frameworkCSS)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Inject user CSS
|
// Inject user CSS
|
||||||
if w.config.CSS != "" {
|
if w.config.GetCSS() != "" {
|
||||||
outputCSS := fmt.Sprintf("%.45s", w.config.CSS)
|
outputCSS := fmt.Sprintf("%.45s", w.config.GetCSS())
|
||||||
if len(outputCSS) > 45 {
|
if len(outputCSS) > 45 {
|
||||||
outputCSS += "..."
|
outputCSS += "..."
|
||||||
}
|
}
|
||||||
w.log.DebugFields("Inject User CSS", Fields{"css": outputCSS})
|
w.log.DebugFields("Inject User CSS", logger.Fields{"css": outputCSS})
|
||||||
w.injectCSS(w.config.CSS)
|
w.injectCSS(w.config.GetCSS())
|
||||||
} else {
|
} else {
|
||||||
// Use default wails css
|
// Use default wails css
|
||||||
w.log.Debug("Injecting Default Wails CSS")
|
w.log.Debug("Injecting Default Wails CSS")
|
||||||
defaultCSS := mewn.String("./wailsruntimeassets/default/wails.css")
|
defaultCSS := mewn.String("../../runtime/assets/wails.css")
|
||||||
|
|
||||||
w.injectCSS(defaultCSS)
|
w.injectCSS(defaultCSS)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject user JS
|
// Inject user JS
|
||||||
if w.config.JS != "" {
|
if w.config.GetJS() != "" {
|
||||||
outputJS := fmt.Sprintf("%.45s", w.config.JS)
|
outputJS := fmt.Sprintf("%.45s", w.config.GetJS())
|
||||||
if len(outputJS) > 45 {
|
if len(outputJS) > 45 {
|
||||||
outputJS += "..."
|
outputJS += "..."
|
||||||
}
|
}
|
||||||
w.log.DebugFields("Inject User JS", Fields{"js": outputJS})
|
w.log.DebugFields("Inject User JS", logger.Fields{"js": outputJS})
|
||||||
w.evalJSSync(w.config.JS)
|
w.evalJSSync(w.config.GetJS())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit that everything is loaded and ready
|
// Emit that everything is loaded and ready
|
||||||
@@ -213,14 +228,15 @@ func (w *webViewRenderer) Run() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Binds the given method name with the front end
|
// NewBinding registers a new binding with the frontend
|
||||||
func (w *webViewRenderer) NewBinding(methodName string) error {
|
func (w *WebView) NewBinding(methodName string) error {
|
||||||
objectCode := fmt.Sprintf("window.wails._.newBinding('%s');", methodName)
|
objectCode := fmt.Sprintf("window.wails._.NewBinding('%s');", methodName)
|
||||||
w.bindingCache = append(w.bindingCache, objectCode)
|
w.bindingCache = append(w.bindingCache, objectCode)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) SelectFile() string {
|
// SelectFile opens a dialog that allows the user to select a file
|
||||||
|
func (w *WebView) SelectFile() string {
|
||||||
var result string
|
var result string
|
||||||
|
|
||||||
// We need to run this on the main thread, however Dispatch is
|
// We need to run this on the main thread, however Dispatch is
|
||||||
@@ -230,7 +246,7 @@ func (w *webViewRenderer) SelectFile() string {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
result = w.window.Dialog(webview.DialogTypeOpen, 0, "Select File", "")
|
result = w.window.Dialog(wv.DialogTypeOpen, 0, "Select File", "")
|
||||||
wg.Done()
|
wg.Done()
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
@@ -238,7 +254,8 @@ func (w *webViewRenderer) SelectFile() string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) SelectDirectory() string {
|
// SelectDirectory opens a dialog that allows the user to select a directory
|
||||||
|
func (w *WebView) SelectDirectory() string {
|
||||||
var result string
|
var result string
|
||||||
// We need to run this on the main thread, however Dispatch is
|
// We need to run this on the main thread, however Dispatch is
|
||||||
// non-blocking so we launch this in a goroutine and wait for
|
// non-blocking so we launch this in a goroutine and wait for
|
||||||
@@ -247,7 +264,7 @@ func (w *webViewRenderer) SelectDirectory() string {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
result = w.window.Dialog(webview.DialogTypeOpen, webview.DialogFlagDirectory, "Select Directory", "")
|
result = w.window.Dialog(wv.DialogTypeOpen, wv.DialogFlagDirectory, "Select Directory", "")
|
||||||
wg.Done()
|
wg.Done()
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
@@ -255,7 +272,8 @@ func (w *webViewRenderer) SelectDirectory() string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) SelectSaveFile() string {
|
// SelectSaveFile opens a dialog that allows the user to select a file to save
|
||||||
|
func (w *WebView) SelectSaveFile() string {
|
||||||
var result string
|
var result string
|
||||||
// We need to run this on the main thread, however Dispatch is
|
// We need to run this on the main thread, however Dispatch is
|
||||||
// non-blocking so we launch this in a goroutine and wait for
|
// non-blocking so we launch this in a goroutine and wait for
|
||||||
@@ -264,7 +282,7 @@ func (w *webViewRenderer) SelectSaveFile() string {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
result = w.window.Dialog(webview.DialogTypeSave, 0, "Save file", "")
|
result = w.window.Dialog(wv.DialogTypeSave, 0, "Save file", "")
|
||||||
wg.Done()
|
wg.Done()
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
@@ -273,18 +291,19 @@ func (w *webViewRenderer) SelectSaveFile() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Callback sends a callback to the frontend
|
// Callback sends a callback to the frontend
|
||||||
func (w *webViewRenderer) Callback(data string) error {
|
func (w *WebView) Callback(data string) error {
|
||||||
callbackCMD := fmt.Sprintf("window.wails._.callback('%s');", data)
|
callbackCMD := fmt.Sprintf("window.wails._.Callback('%s');", data)
|
||||||
return w.evalJS(callbackCMD)
|
return w.evalJS(callbackCMD)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) NotifyEvent(event *eventData) error {
|
// NotifyEvent notifies the frontend about a backend runtime event
|
||||||
|
func (w *WebView) NotifyEvent(event *messages.EventData) error {
|
||||||
|
|
||||||
// Look out! Nils about!
|
// Look out! Nils about!
|
||||||
var err error
|
var err error
|
||||||
if event == nil {
|
if event == nil {
|
||||||
err = fmt.Errorf("Sent nil event to renderer.webViewRenderer")
|
err = fmt.Errorf("Sent nil event to renderer.WebView")
|
||||||
logger.Error(err)
|
w.log.Error(err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,13 +320,13 @@ func (w *webViewRenderer) NotifyEvent(event *eventData) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message := fmt.Sprintf("wails._.notify('%s','%s')", event.Name, data)
|
message := fmt.Sprintf("wails._.Notify('%s','%s')", event.Name, data)
|
||||||
return w.evalJS(message)
|
return w.evalJS(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Window
|
// Fullscreen makes the main window go fullscreen
|
||||||
func (w *webViewRenderer) Fullscreen() {
|
func (w *WebView) Fullscreen() {
|
||||||
if w.config.Resizable == false {
|
if w.config.GetResizable() == false {
|
||||||
w.log.Warn("Cannot call Fullscreen() - App.Resizable = false")
|
w.log.Warn("Cannot call Fullscreen() - App.Resizable = false")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -316,8 +335,9 @@ func (w *webViewRenderer) Fullscreen() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) UnFullscreen() {
|
// UnFullscreen returns the window to the position prior to a fullscreen call
|
||||||
if w.config.Resizable == false {
|
func (w *WebView) UnFullscreen() {
|
||||||
|
if w.config.GetResizable() == false {
|
||||||
w.log.Warn("Cannot call UnFullscreen() - App.Resizable = false")
|
w.log.Warn("Cannot call UnFullscreen() - App.Resizable = false")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -326,13 +346,15 @@ func (w *webViewRenderer) UnFullscreen() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) SetTitle(title string) {
|
// SetTitle sets the window title
|
||||||
|
func (w *WebView) SetTitle(title string) {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
w.window.SetTitle(title)
|
w.window.SetTitle(title)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) Close() {
|
// Close closes the window
|
||||||
|
func (w *WebView) Close() {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
w.window.Terminate()
|
w.window.Terminate()
|
||||||
})
|
})
|
||||||
21
lib/renderer/webview/LICENSE
Normal file
21
lib/renderer/webview/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Serge Zaitsev
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
372
lib/renderer/webview/webview.go
Executable file
372
lib/renderer/webview/webview.go
Executable file
@@ -0,0 +1,372 @@
|
|||||||
|
// Package wails implements Go bindings to https://github.com/zserge/webview C library.
|
||||||
|
// It is a modified version of webview.go from that repository
|
||||||
|
|
||||||
|
// Bindings closely repeat the C APIs and include both, a simplified
|
||||||
|
// single-function API to just open a full-screen webview window, and a more
|
||||||
|
// advanced and featureful set of APIs, including Go-to-JavaScript bindings.
|
||||||
|
//
|
||||||
|
// The library uses gtk-webkit, Cocoa/Webkit and MSHTML (IE8..11) as a browser
|
||||||
|
// engine and supports Linux, MacOS and Windows 7..10 respectively.
|
||||||
|
//
|
||||||
|
package webview
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo linux openbsd freebsd CFLAGS: -DWEBVIEW_GTK=1
|
||||||
|
#cgo linux openbsd freebsd pkg-config: gtk+-3.0 webkit2gtk-4.0
|
||||||
|
|
||||||
|
#cgo windows CFLAGS: -DWEBVIEW_WINAPI=1
|
||||||
|
#cgo windows LDFLAGS: -lole32 -lcomctl32 -loleaut32 -luuid -lgdi32
|
||||||
|
|
||||||
|
#cgo darwin CFLAGS: -DWEBVIEW_COCOA=1 -x objective-c
|
||||||
|
#cgo darwin LDFLAGS: -framework Cocoa -framework WebKit
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#define WEBVIEW_STATIC
|
||||||
|
#define WEBVIEW_IMPLEMENTATION
|
||||||
|
#include "webview.h"
|
||||||
|
|
||||||
|
extern void _webviewExternalInvokeCallback(void *, void *);
|
||||||
|
|
||||||
|
static inline void CgoWebViewFree(void *w) {
|
||||||
|
free((void *)((struct webview *)w)->title);
|
||||||
|
free((void *)((struct webview *)w)->url);
|
||||||
|
free(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *CgoWebViewCreate(int width, int height, char *title, char *url, int resizable, int debug) {
|
||||||
|
struct webview *w = (struct webview *) calloc(1, sizeof(*w));
|
||||||
|
w->width = width;
|
||||||
|
w->height = height;
|
||||||
|
w->title = title;
|
||||||
|
w->url = url;
|
||||||
|
w->resizable = resizable;
|
||||||
|
w->debug = debug;
|
||||||
|
w->external_invoke_cb = (webview_external_invoke_cb_t) _webviewExternalInvokeCallback;
|
||||||
|
if (webview_init(w) != 0) {
|
||||||
|
CgoWebViewFree(w);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return (void *)w;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int CgoWebViewLoop(void *w, int blocking) {
|
||||||
|
return webview_loop((struct webview *)w, blocking);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void CgoWebViewTerminate(void *w) {
|
||||||
|
webview_terminate((struct webview *)w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void CgoWebViewExit(void *w) {
|
||||||
|
webview_exit((struct webview *)w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void CgoWebViewSetTitle(void *w, char *title) {
|
||||||
|
webview_set_title((struct webview *)w, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void CgoWebViewSetFullscreen(void *w, int fullscreen) {
|
||||||
|
webview_set_fullscreen((struct webview *)w, fullscreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void CgoWebViewSetColor(void *w, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||||
|
webview_set_color((struct webview *)w, r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void CgoDialog(void *w, int dlgtype, int flags,
|
||||||
|
char *title, char *arg, char *res, size_t ressz) {
|
||||||
|
webview_dialog(w, dlgtype, flags,
|
||||||
|
(const char*)title, (const char*) arg, res, ressz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int CgoWebViewEval(void *w, char *js) {
|
||||||
|
return webview_eval((struct webview *)w, js);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void CgoWebViewInjectCSS(void *w, char *css) {
|
||||||
|
webview_inject_css((struct webview *)w, css);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void _webviewDispatchGoCallback(void *);
|
||||||
|
static inline void _webview_dispatch_cb(struct webview *w, void *arg) {
|
||||||
|
_webviewDispatchGoCallback(arg);
|
||||||
|
}
|
||||||
|
static inline void CgoWebViewDispatch(void *w, uintptr_t arg) {
|
||||||
|
webview_dispatch((struct webview *)w, _webview_dispatch_cb, (void *)arg);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Ensure that main.main is called from the main thread
|
||||||
|
runtime.LockOSThread()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open is a simplified API to open a single native window with a full-size webview in
|
||||||
|
// it. It can be helpful if you want to communicate with the core app using XHR
|
||||||
|
// or WebSockets (as opposed to using JavaScript bindings).
|
||||||
|
//
|
||||||
|
// Window appearance can be customized using title, width, height and resizable parameters.
|
||||||
|
// URL must be provided and can user either a http or https protocol, or be a
|
||||||
|
// local file:// URL. On some platforms "data:" URLs are also supported
|
||||||
|
// (Linux/MacOS).
|
||||||
|
func Open(title, url string, w, h int, resizable bool) error {
|
||||||
|
titleStr := C.CString(title)
|
||||||
|
defer C.free(unsafe.Pointer(titleStr))
|
||||||
|
urlStr := C.CString(url)
|
||||||
|
defer C.free(unsafe.Pointer(urlStr))
|
||||||
|
resize := C.int(0)
|
||||||
|
if resizable {
|
||||||
|
resize = C.int(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := C.webview(titleStr, urlStr, C.int(w), C.int(h), resize)
|
||||||
|
if r != 0 {
|
||||||
|
return errors.New("failed to create webview")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalInvokeCallbackFunc is a function type that is called every time
|
||||||
|
// "window.external.invoke()" is called from JavaScript. Data is the only
|
||||||
|
// obligatory string parameter passed into the "invoke(data)" function from
|
||||||
|
// JavaScript. To pass more complex data serialized JSON or base64 encoded
|
||||||
|
// string can be used.
|
||||||
|
type ExternalInvokeCallbackFunc func(w WebView, data string)
|
||||||
|
|
||||||
|
// Settings is a set of parameters to customize the initial WebView appearance
|
||||||
|
// and behavior. It is passed into the webview.New() constructor.
|
||||||
|
type Settings struct {
|
||||||
|
// WebView main window title
|
||||||
|
Title string
|
||||||
|
// URL to open in a webview
|
||||||
|
URL string
|
||||||
|
// Window width in pixels
|
||||||
|
Width int
|
||||||
|
// Window height in pixels
|
||||||
|
Height int
|
||||||
|
// Allows/disallows window resizing
|
||||||
|
Resizable bool
|
||||||
|
// Enable debugging tools (Linux/BSD/MacOS, on Windows use Firebug)
|
||||||
|
Debug bool
|
||||||
|
// A callback that is executed when JavaScript calls "window.external.invoke()"
|
||||||
|
ExternalInvokeCallback ExternalInvokeCallbackFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebView is an interface that wraps the basic methods for controlling the UI
|
||||||
|
// loop, handling multithreading and providing JavaScript bindings.
|
||||||
|
type WebView interface {
|
||||||
|
// Run() starts the main UI loop until the user closes the webview window or
|
||||||
|
// Terminate() is called.
|
||||||
|
Run()
|
||||||
|
// Loop() runs a single iteration of the main UI.
|
||||||
|
Loop(blocking bool) bool
|
||||||
|
// SetTitle() changes window title. This method must be called from the main
|
||||||
|
// thread only. See Dispatch() for more details.
|
||||||
|
SetTitle(title string)
|
||||||
|
// SetFullscreen() controls window full-screen mode. This method must be
|
||||||
|
// called from the main thread only. See Dispatch() for more details.
|
||||||
|
SetFullscreen(fullscreen bool)
|
||||||
|
// SetColor() changes window background color. This method must be called from
|
||||||
|
// the main thread only. See Dispatch() for more details.
|
||||||
|
SetColor(r, g, b, a uint8)
|
||||||
|
// Eval() evaluates an arbitrary JS code inside the webview. This method must
|
||||||
|
// be called from the main thread only. See Dispatch() for more details.
|
||||||
|
Eval(js string) error
|
||||||
|
// InjectJS() injects an arbitrary block of CSS code using the JS API. This
|
||||||
|
// method must be called from the main thread only. See Dispatch() for more
|
||||||
|
// details.
|
||||||
|
InjectCSS(css string)
|
||||||
|
// Dialog() opens a system dialog of the given type and title. String
|
||||||
|
// argument can be provided for certain dialogs, such as alert boxes. For
|
||||||
|
// alert boxes argument is a message inside the dialog box.
|
||||||
|
Dialog(dlgType DialogType, flags int, title string, arg string) string
|
||||||
|
// Terminate() breaks the main UI loop. This method must be called from the main thread
|
||||||
|
// only. See Dispatch() for more details.
|
||||||
|
Terminate()
|
||||||
|
// Dispatch() schedules some arbitrary function to be executed on the main UI
|
||||||
|
// thread. This may be helpful if you want to run some JavaScript from
|
||||||
|
// background threads/goroutines, or to terminate the app.
|
||||||
|
Dispatch(func())
|
||||||
|
// Exit() closes the window and cleans up the resources. Use Terminate() to
|
||||||
|
// forcefully break out of the main UI loop.
|
||||||
|
Exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialogType is an enumeration of all supported system dialog types
|
||||||
|
type DialogType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DialogTypeOpen is a system file open dialog
|
||||||
|
DialogTypeOpen DialogType = iota
|
||||||
|
// DialogTypeSave is a system file save dialog
|
||||||
|
DialogTypeSave
|
||||||
|
// DialogTypeAlert is a system alert dialog (message box)
|
||||||
|
DialogTypeAlert
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DialogFlagFile is a normal file picker dialog
|
||||||
|
DialogFlagFile = C.WEBVIEW_DIALOG_FLAG_FILE
|
||||||
|
// DialogFlagDirectory is an open directory dialog
|
||||||
|
DialogFlagDirectory = C.WEBVIEW_DIALOG_FLAG_DIRECTORY
|
||||||
|
// DialogFlagInfo is an info alert dialog
|
||||||
|
DialogFlagInfo = C.WEBVIEW_DIALOG_FLAG_INFO
|
||||||
|
// DialogFlagWarning is a warning alert dialog
|
||||||
|
DialogFlagWarning = C.WEBVIEW_DIALOG_FLAG_WARNING
|
||||||
|
// DialogFlagError is an error dialog
|
||||||
|
DialogFlagError = C.WEBVIEW_DIALOG_FLAG_ERROR
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
m sync.Mutex
|
||||||
|
index uintptr
|
||||||
|
fns = map[uintptr]func(){}
|
||||||
|
cbs = map[WebView]ExternalInvokeCallbackFunc{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type webview struct {
|
||||||
|
w unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ WebView = &webview{}
|
||||||
|
|
||||||
|
func boolToInt(b bool) int {
|
||||||
|
if b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWebview creates and opens a new webview window using the given settings. The
|
||||||
|
// returned object implements the WebView interface. This function returns nil
|
||||||
|
// if a window can not be created.
|
||||||
|
func NewWebview(settings Settings) WebView {
|
||||||
|
if settings.Width == 0 {
|
||||||
|
settings.Width = 640
|
||||||
|
}
|
||||||
|
if settings.Height == 0 {
|
||||||
|
settings.Height = 480
|
||||||
|
}
|
||||||
|
if settings.Title == "" {
|
||||||
|
settings.Title = "WebView"
|
||||||
|
}
|
||||||
|
w := &webview{}
|
||||||
|
w.w = C.CgoWebViewCreate(C.int(settings.Width), C.int(settings.Height),
|
||||||
|
C.CString(settings.Title), C.CString(settings.URL),
|
||||||
|
C.int(boolToInt(settings.Resizable)), C.int(boolToInt(settings.Debug)))
|
||||||
|
m.Lock()
|
||||||
|
if settings.ExternalInvokeCallback != nil {
|
||||||
|
cbs[w] = settings.ExternalInvokeCallback
|
||||||
|
} else {
|
||||||
|
cbs[w] = func(w WebView, data string) {}
|
||||||
|
}
|
||||||
|
m.Unlock()
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *webview) Loop(blocking bool) bool {
|
||||||
|
block := C.int(0)
|
||||||
|
if blocking {
|
||||||
|
block = 1
|
||||||
|
}
|
||||||
|
return C.CgoWebViewLoop(w.w, block) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *webview) Run() {
|
||||||
|
for w.Loop(true) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *webview) Exit() {
|
||||||
|
C.CgoWebViewExit(w.w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *webview) Dispatch(f func()) {
|
||||||
|
m.Lock()
|
||||||
|
for ; fns[index] != nil; index++ {
|
||||||
|
}
|
||||||
|
fns[index] = f
|
||||||
|
m.Unlock()
|
||||||
|
C.CgoWebViewDispatch(w.w, C.uintptr_t(index))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *webview) SetTitle(title string) {
|
||||||
|
p := C.CString(title)
|
||||||
|
defer C.free(unsafe.Pointer(p))
|
||||||
|
C.CgoWebViewSetTitle(w.w, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *webview) SetColor(r, g, b, a uint8) {
|
||||||
|
C.CgoWebViewSetColor(w.w, C.uint8_t(r), C.uint8_t(g), C.uint8_t(b), C.uint8_t(a))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *webview) SetFullscreen(fullscreen bool) {
|
||||||
|
C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string) string {
|
||||||
|
const maxPath = 4096
|
||||||
|
titlePtr := C.CString(title)
|
||||||
|
defer C.free(unsafe.Pointer(titlePtr))
|
||||||
|
argPtr := C.CString(arg)
|
||||||
|
defer C.free(unsafe.Pointer(argPtr))
|
||||||
|
resultPtr := (*C.char)(C.calloc((C.size_t)(unsafe.Sizeof((*C.char)(nil))), (C.size_t)(maxPath)))
|
||||||
|
defer C.free(unsafe.Pointer(resultPtr))
|
||||||
|
C.CgoDialog(w.w, C.int(dlgType), C.int(flags), titlePtr,
|
||||||
|
argPtr, resultPtr, C.size_t(maxPath))
|
||||||
|
return C.GoString(resultPtr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *webview) Eval(js string) error {
|
||||||
|
p := C.CString(js)
|
||||||
|
defer C.free(unsafe.Pointer(p))
|
||||||
|
switch C.CgoWebViewEval(w.w, p) {
|
||||||
|
case -1:
|
||||||
|
return errors.New("evaluation failed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *webview) InjectCSS(css string) {
|
||||||
|
p := C.CString(css)
|
||||||
|
defer C.free(unsafe.Pointer(p))
|
||||||
|
C.CgoWebViewInjectCSS(w.w, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *webview) Terminate() {
|
||||||
|
C.CgoWebViewTerminate(w.w)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export _webviewDispatchGoCallback
|
||||||
|
func _webviewDispatchGoCallback(index unsafe.Pointer) {
|
||||||
|
var f func()
|
||||||
|
m.Lock()
|
||||||
|
f = fns[uintptr(index)]
|
||||||
|
delete(fns, uintptr(index))
|
||||||
|
m.Unlock()
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
//export _webviewExternalInvokeCallback
|
||||||
|
func _webviewExternalInvokeCallback(w unsafe.Pointer, data unsafe.Pointer) {
|
||||||
|
m.Lock()
|
||||||
|
var (
|
||||||
|
cb ExternalInvokeCallbackFunc
|
||||||
|
wv WebView
|
||||||
|
)
|
||||||
|
for wv, cb = range cbs {
|
||||||
|
if wv.(*webview).w == w {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.Unlock()
|
||||||
|
cb(wv, C.GoString((*C.char)(data)))
|
||||||
|
}
|
||||||
2244
lib/renderer/webview/webview.h
Normal file
2244
lib/renderer/webview/webview.h
Normal file
File diff suppressed because it is too large
Load Diff
42
log.go
42
log.go
@@ -1,42 +0,0 @@
|
|||||||
package wails
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Global logger reference
|
|
||||||
var logger = log.New()
|
|
||||||
|
|
||||||
// Fields is used by the customLogger object to output
|
|
||||||
// fields along with a message
|
|
||||||
type Fields map[string]interface{}
|
|
||||||
|
|
||||||
// Default options for the global logger
|
|
||||||
func init() {
|
|
||||||
logger.SetOutput(os.Stdout)
|
|
||||||
logger.SetLevel(log.DebugLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the log level to the given level
|
|
||||||
func setLogLevel(level string) {
|
|
||||||
switch strings.ToLower(level) {
|
|
||||||
case "info":
|
|
||||||
logger.SetLevel(log.InfoLevel)
|
|
||||||
case "debug":
|
|
||||||
logger.SetLevel(log.DebugLevel)
|
|
||||||
case "warn":
|
|
||||||
logger.SetLevel(log.WarnLevel)
|
|
||||||
case "error":
|
|
||||||
logger.SetLevel(log.ErrorLevel)
|
|
||||||
case "fatal":
|
|
||||||
logger.SetLevel(log.FatalLevel)
|
|
||||||
case "panic":
|
|
||||||
logger.SetLevel(log.PanicLevel)
|
|
||||||
default:
|
|
||||||
logger.SetLevel(log.DebugLevel)
|
|
||||||
logger.Warnf("Log level '%s' not recognised. Setting to Debug.", level)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
36
runtime.go
36
runtime.go
@@ -1,22 +1,32 @@
|
|||||||
package wails
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CustomLogger type alias
|
||||||
|
type CustomLogger = logger.CustomLogger
|
||||||
|
|
||||||
// Runtime is the Wails Runtime Interface, given to a user who has defined the WailsInit method
|
// Runtime is the Wails Runtime Interface, given to a user who has defined the WailsInit method
|
||||||
type Runtime struct {
|
type Runtime struct {
|
||||||
Events *RuntimeEvents
|
Events *runtime.Events
|
||||||
Log *RuntimeLog
|
Log *runtime.Log
|
||||||
Dialog *RuntimeDialog
|
Dialog *runtime.Dialog
|
||||||
Window *RuntimeWindow
|
Window *runtime.Window
|
||||||
Browser *RuntimeBrowser
|
Browser *runtime.Browser
|
||||||
FileSystem *RuntimeFileSystem
|
FileSystem *runtime.FileSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRuntime(eventManager *eventManager, renderer Renderer) *Runtime {
|
// NewRuntime creates a new Runtime struct
|
||||||
|
func NewRuntime(eventManager interfaces.EventManager, renderer interfaces.Renderer) *Runtime {
|
||||||
return &Runtime{
|
return &Runtime{
|
||||||
Events: newRuntimeEvents(eventManager),
|
Events: runtime.NewEvents(eventManager),
|
||||||
Log: newRuntimeLog(),
|
Log: runtime.NewLog(),
|
||||||
Dialog: newRuntimeDialog(renderer),
|
Dialog: runtime.NewDialog(renderer),
|
||||||
Window: newRuntimeWindow(renderer),
|
Window: runtime.NewWindow(renderer),
|
||||||
Browser: newRuntimeBrowser(),
|
Browser: runtime.NewBrowser(),
|
||||||
FileSystem: newRuntimeFileSystem(),
|
FileSystem: runtime.NewFileSystem(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
Wails Bridge (c) 2019-present Lea Anthony
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
This library creates a bridge between your application
|
| | /| / / __ `/ / / ___/
|
||||||
and the frontend, allowing you to develop your app using
|
| |/ |/ / /_/ / / (__ )
|
||||||
standard tooling (browser extensions, live reload, etc).
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
Usage:
|
(c) Lea Anthony 2019-present
|
||||||
```
|
|
||||||
import Bridge from "./wailsbridge";
|
|
||||||
Bridge.Start(startApp);
|
|
||||||
```
|
|
||||||
|
|
||||||
The given callback (startApp in the example) will be called
|
|
||||||
when the bridge has successfully initialised. It passes the
|
|
||||||
window.wails object back, in case it is not accessible directly.
|
|
||||||
*/
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
// Bridge object
|
function init() {
|
||||||
window.wailsbridge = {
|
// Bridge object
|
||||||
|
window.wailsbridge = {
|
||||||
reconnectOverlay: null,
|
reconnectOverlay: null,
|
||||||
reconnectTimer: 300,
|
reconnectTimer: 300,
|
||||||
wsURL: 'ws://localhost:34115/bridge',
|
wsURL: 'ws://localhost:34115/bridge',
|
||||||
@@ -37,7 +31,8 @@ window.wailsbridge = {
|
|||||||
'background: #009900; color: #fff; border-radius: 0px 3px 3px 0px; padding: 1px; font-size: 0.7rem'
|
'background: #009900; color: #fff; border-radius: 0px 3px 3px 0px; padding: 1px; font-size: 0.7rem'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Adapted from webview - thanks zserge!
|
// Adapted from webview - thanks zserge!
|
||||||
function injectCSS(css) {
|
function injectCSS(css) {
|
||||||
@@ -184,12 +179,12 @@ function startBridge() {
|
|||||||
case 'b':
|
case 'b':
|
||||||
var binding = message.data.slice(1);
|
var binding = message.data.slice(1);
|
||||||
//log("Binding: " + binding)
|
//log("Binding: " + binding)
|
||||||
window.wails._.newBinding(binding);
|
window.wails._.NewBinding(binding);
|
||||||
break;
|
break;
|
||||||
// Call back
|
// Call back
|
||||||
case 'c':
|
case 'c':
|
||||||
var callbackData = message.data.slice(1);
|
var callbackData = message.data.slice(1);
|
||||||
window.wails._.callback(callbackData);
|
window.wails._.Callback(callbackData);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
window.wails.Log.Error('Unknown message type received: ' + message.data[0]);
|
window.wails.Log.Error('Unknown message type received: ' + message.data[0]);
|
||||||
@@ -203,14 +198,20 @@ function startBridge() {
|
|||||||
connect();
|
connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
function start(callback) {
|
||||||
// The main function
|
|
||||||
// Passes the main Wails object to the callback if given.
|
// Set up the bridge
|
||||||
Start: function (callback) {
|
init();
|
||||||
|
|
||||||
// Save the callback
|
// Save the callback
|
||||||
window.wailsbridge.callback = callback;
|
window.wailsbridge.callback = callback;
|
||||||
|
|
||||||
// Start Bridge
|
// Start Bridge
|
||||||
startBridge();
|
startBridge();
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
function Init(callback) {
|
||||||
|
start(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { Init };
|
||||||
18
runtime/assets/default.html
Normal file
18
runtime/assets/default.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="text/javascript">function AddScript(js, callbackID) {
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.text = js;
|
||||||
|
document.body.appendChild(script);
|
||||||
|
}</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
1
runtime/assets/wails.js
Normal file
1
runtime/assets/wails.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
!function(n){var t={};function e(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return n[r].call(o.exports,o,o.exports,e),o.l=!0,o.exports}e.m=n,e.c=t,e.d=function(n,t,r){e.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:r})},e.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},e.t=function(n,t){if(1&t&&(n=e(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var r=Object.create(null);if(e.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var o in n)e.d(r,o,function(t){return n[t]}.bind(null,o));return r},e.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,"a",t),t},e.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},e.p="",e(e.s=0)}([function(n,t,e){"use strict";e.r(t);var r={};e.r(r),e.d(r,"Debug",function(){return c}),e.d(r,"Info",function(){return u}),e.d(r,"Warning",function(){return l}),e.d(r,"Error",function(){return f}),e.d(r,"Fatal",function(){return d});var o={};function a(n,t,e){var r={type:n,callbackID:e,payload:t};!function(n){window.external.invoke(n)}(JSON.stringify(r))}function i(n,t){a("log",{level:n,message:t})}function c(n){i("debug",n)}function u(n){i("info",n)}function l(n){i("warning",n)}function f(n){i("error",n)}function d(n){i("fatal",n)}e.r(o),e.d(o,"OpenURL",function(){return y}),e.d(o,"OpenFile",function(){return g});var s,p={};function v(n,t,e){return null!=e&&null!=e||(e=0),new Promise(function(r,o){var i;do{i=n+"-"+s()}while(p[i]);if(e>0)var c=setTimeout(function(){o(Error("Call to "+n+" timed out. Request ID: "+i))},e);p[i]={timeoutHandle:c,reject:o,resolve:r};try{a("call",{bindingName:n,data:JSON.stringify(t)},i)}catch(n){console.error(n)}})}function w(n,t){return v(".wails."+n,t)}function y(n){return w("Browser.OpenURL",n)}function g(n){return w("Browser.OpenFile",n)}s=window.crypto?function(){var n=new Uint32Array(1);return window.crypto.getRandomValues(n)[0]}:function(){return 9007199254740991*Math.random()};var m=function n(t,e){!function(n,t){if(!(n instanceof t))throw new TypeError("Cannot call a class as a function")}(this,n),e=e||-1,this.Callback=function(n){return t.apply(null,n),-1!==e&&0===(e-=1)}},b={};function h(n,t,e){b[n]=b[n]||[];var r=new m(t,e);b[n].push(r)}function O(n){a("event",{name:n,data:JSON.stringify([].slice.apply(arguments).slice(1))})}var S={};function j(n){try{return new Function("var "+n),!0}catch(n){return!1}}function k(){return(k=Object.assign||function(n){for(var t=1;t<arguments.length;t++){var e=arguments[t];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r])}return n}).apply(this,arguments)}window.backend={},e.d(t,"Init",function(){return N}),window.wails=window.wails||{},window.backend={};var E={NewBinding:function(n){var t=[].concat(n.split(".").splice(1)),e=window.backend;if(t.length>1)for(var r=0;r<t.length-1;r+=1){var o=t[r];if(!j(o))return new Error("".concat(o," is not a valid javascript identifier."));e[o]={},e=e[o]}var a=t.pop();if(!j(a))return new Error("".concat(a," is not a valid javascript identifier."));e[a]=function(){var t=0;function e(){var e=[].slice.call(arguments);return v(n,e,t)}return e.setTimeout=function(n){t=n},e.getTimeout=function(){return t},e}()},Callback:function(n){var t;n=decodeURIComponent(n.replace(/\s+/g,"").replace(/[0-9a-f]{2}/g,"%$&"));try{t=JSON.parse(n)}catch(t){var e="Invalid JSON passed to callback: ".concat(t.message,". Message: ").concat(n);throw c(e),new Error(e)}var r=t.callbackid,o=p[r];if(!o){var a="Callback '".concat(r,"' not registed!!!");throw console.error(a),new Error(a)}clearTimeout(o.timeoutHandle),delete p[r],t.error?o.reject(t.error):o.resolve(t.data)},Notify:function(n,t){if(b[n]){for(var e=b[n].slice(),r=0;r<b[n].length;r+=1){var o=b[n][r],a=[];if(t)try{a=JSON.parse(t)}catch(t){f("Invalid JSON data sent to notify. Event name = "+n)}o.Callback(a)&&e.splice(r,1)}b[n]=e}},AddScript:function(n,t){var e=document.createElement("script");e.text=n,document.body.appendChild(e),t&&O(t)},InjectCSS:function(n){var t=document.createElement("style");t.setAttribute("type","text/css"),t.styleSheet?t.styleSheet.cssText=n:t.appendChild(document.createTextNode(n)),(document.head||document.getElementsByTagName("head")[0]).appendChild(t)},Init:N},C={Log:r,Browser:o,Events:{On:function(n,t){h(n,t)},Emit:O,Heartbeat:function(n,t,e){var r=null;S[n]=function(){clearInterval(r),e()},r=setInterval(function(){O(n)},t)},Acknowledge:function(n){if(!S[n])throw new f("Cannot acknowledge unknown heartbeat '".concat(n,"'"));S[n]()}},_:E};function N(n){n()}k(window.wails,C),O("wails:loaded")}]);
|
||||||
21
runtime/browser.go
Normal file
21
runtime/browser.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import "github.com/pkg/browser"
|
||||||
|
|
||||||
|
// Browser exposes browser methods to the runtime
|
||||||
|
type Browser struct{}
|
||||||
|
|
||||||
|
// NewBrowser creates a new runtime Browser struct
|
||||||
|
func NewBrowser() *Browser {
|
||||||
|
return &Browser{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenURL opens the given url in the system's default browser
|
||||||
|
func (r *Browser) OpenURL(url string) error {
|
||||||
|
return browser.OpenURL(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenFile opens the given file in the system's default browser
|
||||||
|
func (r *Browser) OpenFile(filePath string) error {
|
||||||
|
return browser.OpenFile(filePath)
|
||||||
|
}
|
||||||
30
runtime/dialog.go
Normal file
30
runtime/dialog.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import "github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
|
||||||
|
// Dialog exposes an interface to native dialogs
|
||||||
|
type Dialog struct {
|
||||||
|
renderer interfaces.Renderer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDialog creates a new Dialog struct
|
||||||
|
func NewDialog(renderer interfaces.Renderer) *Dialog {
|
||||||
|
return &Dialog{
|
||||||
|
renderer: renderer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectFile prompts the user to select a file
|
||||||
|
func (r *Dialog) SelectFile() string {
|
||||||
|
return r.renderer.SelectFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDirectory prompts the user to select a directory
|
||||||
|
func (r *Dialog) SelectDirectory() string {
|
||||||
|
return r.renderer.SelectDirectory()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectSaveFile prompts the user to select a file for saving
|
||||||
|
func (r *Dialog) SelectSaveFile() string {
|
||||||
|
return r.renderer.SelectSaveFile()
|
||||||
|
}
|
||||||
25
runtime/events.go
Normal file
25
runtime/events.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import "github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
|
||||||
|
// Events exposes the events interface
|
||||||
|
type Events struct {
|
||||||
|
eventManager interfaces.EventManager
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEvents creates a new Events struct
|
||||||
|
func NewEvents(eventManager interfaces.EventManager) *Events {
|
||||||
|
return &Events{
|
||||||
|
eventManager: eventManager,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// On pass through
|
||||||
|
func (r *Events) On(eventName string, callback func(optionalData ...interface{})) {
|
||||||
|
r.eventManager.On(eventName, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit pass through
|
||||||
|
func (r *Events) Emit(eventName string, optionalData ...interface{}) {
|
||||||
|
r.eventManager.Emit(eventName, optionalData...)
|
||||||
|
}
|
||||||
16
runtime/filesystem.go
Normal file
16
runtime/filesystem.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import homedir "github.com/mitchellh/go-homedir"
|
||||||
|
|
||||||
|
// FileSystem exposes file system utilities to the runtime
|
||||||
|
type FileSystem struct {}
|
||||||
|
|
||||||
|
// NewFileSystem creates a new FileSystem struct
|
||||||
|
func NewFileSystem() *FileSystem {
|
||||||
|
return &FileSystem{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HomeDir returns the user's home directory
|
||||||
|
func (r *FileSystem) HomeDir() (string, error) {
|
||||||
|
return homedir.Dir()
|
||||||
|
}
|
||||||
31
runtime/js/.eslintrc
Normal file
31
runtime/js/.eslintrc
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es6": true,
|
||||||
|
"amd": true,
|
||||||
|
"node": true,
|
||||||
|
},
|
||||||
|
"extends": "eslint:recommended",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 2016,
|
||||||
|
"sourceType": "module",
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"indent": [
|
||||||
|
"error",
|
||||||
|
"tab"
|
||||||
|
],
|
||||||
|
"linebreak-style": [
|
||||||
|
"error",
|
||||||
|
"unix"
|
||||||
|
],
|
||||||
|
"quotes": [
|
||||||
|
"error",
|
||||||
|
"single"
|
||||||
|
],
|
||||||
|
"semi": [
|
||||||
|
"error",
|
||||||
|
"always"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
22
runtime/js/babel.config.js
Normal file
22
runtime/js/babel.config.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
module.exports = function (api) {
|
||||||
|
api.cache(true);
|
||||||
|
|
||||||
|
const presets = [
|
||||||
|
[
|
||||||
|
"@babel/preset-env",
|
||||||
|
{
|
||||||
|
"useBuiltIns": "entry",
|
||||||
|
"corejs": {
|
||||||
|
"version": 3,
|
||||||
|
"proposals": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
presets,
|
||||||
|
};
|
||||||
|
}
|
||||||
92
runtime/js/core/bindings.js
Normal file
92
runtime/js/core/bindings.js
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
import { Call } from './calls';
|
||||||
|
|
||||||
|
window.backend = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the given identifier is valid Javascript
|
||||||
|
*
|
||||||
|
* @param {boolean} name
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function isValidIdentifier(name) {
|
||||||
|
// Don't xss yourself :-)
|
||||||
|
try {
|
||||||
|
new Function('var ' + name);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NewBinding creates a new binding from the given binding name
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} bindingName
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line max-lines-per-function
|
||||||
|
export function NewBinding(bindingName) {
|
||||||
|
|
||||||
|
// Get all the sections of the binding
|
||||||
|
var bindingSections = [].concat(bindingName.split('.').splice(1));
|
||||||
|
var pathToBinding = window.backend;
|
||||||
|
|
||||||
|
// Check if we have a path (IE Struct)
|
||||||
|
if (bindingSections.length > 1) {
|
||||||
|
// Iterate over binding sections, adding them to the window.backend object
|
||||||
|
for (let index = 0; index < bindingSections.length - 1; index += 1) {
|
||||||
|
const name = bindingSections[index];
|
||||||
|
// Is name a valid javascript identifier?
|
||||||
|
if (!isValidIdentifier(name)) {
|
||||||
|
return new Error(`${name} is not a valid javascript identifier.`);
|
||||||
|
}
|
||||||
|
pathToBinding[name] = {};
|
||||||
|
pathToBinding = pathToBinding[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the actual function/method call name
|
||||||
|
const name = bindingSections.pop();
|
||||||
|
|
||||||
|
// Is name a valid javascript identifier?
|
||||||
|
if (!isValidIdentifier(name)) {
|
||||||
|
return new Error(`${name} is not a valid javascript identifier.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add binding call
|
||||||
|
pathToBinding[name] = function () {
|
||||||
|
|
||||||
|
// No timeout by default
|
||||||
|
var timeout = 0;
|
||||||
|
|
||||||
|
// Actual function
|
||||||
|
function dynamic() {
|
||||||
|
var args = [].slice.call(arguments);
|
||||||
|
return Call(bindingName, args, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow setting timeout to function
|
||||||
|
dynamic.setTimeout = function (newTimeout) {
|
||||||
|
timeout = newTimeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Allow getting timeout to function
|
||||||
|
dynamic.getTimeout = function () {
|
||||||
|
return timeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
return dynamic;
|
||||||
|
}();
|
||||||
|
}
|
||||||
34
runtime/js/core/browser.js
Normal file
34
runtime/js/core/browser.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
import { SystemCall } from './calls';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the given URL in the system browser
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} url
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function OpenURL(url) {
|
||||||
|
return SystemCall('Browser.OpenURL', url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the given filename using the system's default file handler
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {sting} filename
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function OpenFile(filename) {
|
||||||
|
return SystemCall('Browser.OpenFile', filename);
|
||||||
|
}
|
||||||
158
runtime/js/core/calls.js
Normal file
158
runtime/js/core/calls.js
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
import { Debug } from './log';
|
||||||
|
import { SendMessage } from './ipc';
|
||||||
|
|
||||||
|
var callbacks = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a number from the native browser random function
|
||||||
|
*
|
||||||
|
* @returns number
|
||||||
|
*/
|
||||||
|
function cryptoRandom() {
|
||||||
|
var array = new Uint32Array(1);
|
||||||
|
return window.crypto.getRandomValues(array)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a number using da old-skool Math.Random
|
||||||
|
* I likes to call it LOLRandom
|
||||||
|
*
|
||||||
|
* @returns number
|
||||||
|
*/
|
||||||
|
function basicRandom() {
|
||||||
|
return Math.random() * 9007199254740991;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pick a random number function based on browser capability
|
||||||
|
var randomFunc;
|
||||||
|
if (window.crypto) {
|
||||||
|
randomFunc = cryptoRandom;
|
||||||
|
} else {
|
||||||
|
randomFunc = basicRandom;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call sends a message to the backend to call the binding with the
|
||||||
|
* given data. A promise is returned and will be completed when the
|
||||||
|
* backend responds. This will be resolved when the call was successful
|
||||||
|
* or rejected if an error is passed back.
|
||||||
|
* There is a timeout mechanism. If the call doesn't respond in the given
|
||||||
|
* time (in milliseconds) then the promise is rejected.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} bindingName
|
||||||
|
* @param {string} data
|
||||||
|
* @param {number=} timeout
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function Call(bindingName, data, timeout) {
|
||||||
|
|
||||||
|
// Timeout infinite by default
|
||||||
|
if (timeout == null || timeout == undefined) {
|
||||||
|
timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a promise
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
|
||||||
|
// Create a unique callbackID
|
||||||
|
var callbackID;
|
||||||
|
do {
|
||||||
|
callbackID = bindingName + '-' + randomFunc();
|
||||||
|
} while (callbacks[callbackID]);
|
||||||
|
|
||||||
|
// Set timeout
|
||||||
|
if (timeout > 0) {
|
||||||
|
var timeoutHandle = setTimeout(function () {
|
||||||
|
reject(Error('Call to ' + bindingName + ' timed out. Request ID: ' + callbackID));
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store callback
|
||||||
|
callbacks[callbackID] = {
|
||||||
|
timeoutHandle: timeoutHandle,
|
||||||
|
reject: reject,
|
||||||
|
resolve: resolve
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const payload = {
|
||||||
|
bindingName: bindingName,
|
||||||
|
data: JSON.stringify(data),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make the call
|
||||||
|
SendMessage('call', payload, callbackID);
|
||||||
|
} catch (e) {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the backend to return data to a previously called
|
||||||
|
* binding invocation
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} incomingMessage
|
||||||
|
*/
|
||||||
|
export function Callback(incomingMessage) {
|
||||||
|
|
||||||
|
// Decode the message - Credit: https://stackoverflow.com/a/13865680
|
||||||
|
incomingMessage = decodeURIComponent(incomingMessage.replace(/\s+/g, '').replace(/[0-9a-f]{2}/g, '%$&'));
|
||||||
|
|
||||||
|
// Parse the message
|
||||||
|
var message;
|
||||||
|
try {
|
||||||
|
message = JSON.parse(incomingMessage);
|
||||||
|
} catch (e) {
|
||||||
|
const error = `Invalid JSON passed to callback: ${e.message}. Message: ${incomingMessage}`;
|
||||||
|
Debug(error);
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
var callbackID = message.callbackid;
|
||||||
|
var callbackData = callbacks[callbackID];
|
||||||
|
if (!callbackData) {
|
||||||
|
const error = `Callback '${callbackID}' not registed!!!`;
|
||||||
|
console.error(error); // eslint-disable-line
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
clearTimeout(callbackData.timeoutHandle);
|
||||||
|
|
||||||
|
delete callbacks[callbackID];
|
||||||
|
|
||||||
|
if (message.error) {
|
||||||
|
callbackData.reject(message.error);
|
||||||
|
} else {
|
||||||
|
callbackData.resolve(message.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SystemCall is used to call wails methods from the frontend
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} method
|
||||||
|
* @param {any[]=} data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function SystemCall(method, data) {
|
||||||
|
return Call('.wails.' + method, data);
|
||||||
|
}
|
||||||
194
runtime/js/core/events.js
Normal file
194
runtime/js/core/events.js
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
import { Error } from './log';
|
||||||
|
import { SendMessage } from './ipc';
|
||||||
|
|
||||||
|
// Defines a single listener with a maximum number of times to callback
|
||||||
|
/**
|
||||||
|
* The Listener class defines a listener! :-)
|
||||||
|
*
|
||||||
|
* @class Listener
|
||||||
|
*/
|
||||||
|
class Listener {
|
||||||
|
/**
|
||||||
|
* Creates an instance of Listener.
|
||||||
|
* @param {function} callback
|
||||||
|
* @param {number} maxCallbacks
|
||||||
|
* @memberof Listener
|
||||||
|
*/
|
||||||
|
constructor(callback, maxCallbacks) {
|
||||||
|
// Default of -1 means infinite
|
||||||
|
maxCallbacks = maxCallbacks || -1;
|
||||||
|
// Callback invokes the callback with the given data
|
||||||
|
// Returns true if this listener should be destroyed
|
||||||
|
this.Callback = (data) => {
|
||||||
|
callback.apply(null, data);
|
||||||
|
// If maxCallbacks is infinite, return false (do not destroy)
|
||||||
|
if (maxCallbacks === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Decrement maxCallbacks. Return true if now 0, otherwise false
|
||||||
|
maxCallbacks -= 1;
|
||||||
|
return maxCallbacks === 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventListeners = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an event listener that will be invoked `maxCallbacks` times before being destroyed
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} eventName
|
||||||
|
* @param {function} callback
|
||||||
|
* @param {number} maxCallbacks
|
||||||
|
*/
|
||||||
|
export function OnMultiple(eventName, callback, maxCallbacks) {
|
||||||
|
eventListeners[eventName] = eventListeners[eventName] || [];
|
||||||
|
const thisListener = new Listener(callback, maxCallbacks);
|
||||||
|
eventListeners[eventName].push(thisListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an event listener that will be invoked every time the event is emitted
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} eventName
|
||||||
|
* @param {function} callback
|
||||||
|
*/
|
||||||
|
export function On(eventName, callback) {
|
||||||
|
OnMultiple(eventName, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an event listener that will be invoked once then destroyed
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} eventName
|
||||||
|
* @param {function} callback
|
||||||
|
*/
|
||||||
|
export function Once(eventName, callback) {
|
||||||
|
OnMultiple(eventName, callback, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify informs frontend listeners that an event was emitted with the given data
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} eventName
|
||||||
|
* @param {string} data
|
||||||
|
*/
|
||||||
|
export function Notify(eventName, data) {
|
||||||
|
|
||||||
|
// Check if we have any listeners for this event
|
||||||
|
if (eventListeners[eventName]) {
|
||||||
|
|
||||||
|
// Keep a list of listener indexes to destroy
|
||||||
|
const newEventListenerList = eventListeners[eventName].slice();
|
||||||
|
|
||||||
|
// Iterate listeners
|
||||||
|
for (let count = 0; count < eventListeners[eventName].length; count += 1) {
|
||||||
|
|
||||||
|
// Get next listener
|
||||||
|
const listener = eventListeners[eventName][count];
|
||||||
|
|
||||||
|
// Parse data if we have it
|
||||||
|
var parsedData = [];
|
||||||
|
if (data) {
|
||||||
|
try {
|
||||||
|
parsedData = JSON.parse(data);
|
||||||
|
} catch (e) {
|
||||||
|
Error('Invalid JSON data sent to notify. Event name = ' + eventName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Do the callback
|
||||||
|
const destroy = listener.Callback(parsedData);
|
||||||
|
if (destroy) {
|
||||||
|
// if the listener indicated to destroy itself, add it to the destroy list
|
||||||
|
newEventListenerList.splice(count, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update callbacks with new list of listners
|
||||||
|
eventListeners[eventName] = newEventListenerList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit an event with the given name and data
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} eventName
|
||||||
|
*/
|
||||||
|
export function Emit(eventName) {
|
||||||
|
|
||||||
|
// Calculate the data
|
||||||
|
var data = JSON.stringify([].slice.apply(arguments).slice(1));
|
||||||
|
|
||||||
|
// Notify backend
|
||||||
|
const payload = {
|
||||||
|
name: eventName,
|
||||||
|
data: data,
|
||||||
|
};
|
||||||
|
SendMessage('event', payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callbacks for the heartbeat calls
|
||||||
|
const heartbeatCallbacks = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Heartbeat emits the event `eventName`, every `timeInMilliseconds` milliseconds until
|
||||||
|
* the event is acknowledged via `Event.Acknowledge`. Once this happens, `callback` is invoked ONCE
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} eventName
|
||||||
|
* @param {number} timeInMilliseconds
|
||||||
|
* @param {function} callback
|
||||||
|
*/
|
||||||
|
export function Heartbeat(eventName, timeInMilliseconds, callback) {
|
||||||
|
|
||||||
|
// Declare interval variable
|
||||||
|
let interval = null;
|
||||||
|
|
||||||
|
// Setup callback
|
||||||
|
function dynamicCallback() {
|
||||||
|
// Kill interval
|
||||||
|
clearInterval(interval);
|
||||||
|
// Callback
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register callback
|
||||||
|
heartbeatCallbacks[eventName] = dynamicCallback;
|
||||||
|
|
||||||
|
// Start emitting the event
|
||||||
|
interval = setInterval(function () {
|
||||||
|
Emit(eventName);
|
||||||
|
}, timeInMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acknowledges a heartbeat event by name
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} eventName
|
||||||
|
*/
|
||||||
|
export function Acknowledge(eventName) {
|
||||||
|
// If we are waiting for acknowledgement for this event type
|
||||||
|
if (heartbeatCallbacks[eventName]) {
|
||||||
|
// Acknowledge!
|
||||||
|
heartbeatCallbacks[eventName]();
|
||||||
|
} else {
|
||||||
|
throw new Error(`Cannot acknowledge unknown heartbeat '${eventName}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
runtime/js/core/ipc.js
Normal file
37
runtime/js/core/ipc.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke sends the given message to the backend
|
||||||
|
*
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
function Invoke(message) {
|
||||||
|
window.external.invoke(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a message to the backend based on the given type, payload and callbackID
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} type
|
||||||
|
* @param {string} payload
|
||||||
|
* @param {string=} callbackID
|
||||||
|
*/
|
||||||
|
export function SendMessage(type, payload, callbackID) {
|
||||||
|
const message = {
|
||||||
|
type,
|
||||||
|
callbackID,
|
||||||
|
payload
|
||||||
|
};
|
||||||
|
|
||||||
|
Invoke(JSON.stringify(message));
|
||||||
|
}
|
||||||
80
runtime/js/core/log.js
Normal file
80
runtime/js/core/log.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
import { SendMessage } from './ipc';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a log message to the backend with the given level + message
|
||||||
|
*
|
||||||
|
* @param {string} level
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
function sendLogMessage(level, message) {
|
||||||
|
|
||||||
|
// Log Message
|
||||||
|
const payload = {
|
||||||
|
level: level,
|
||||||
|
message: message,
|
||||||
|
};
|
||||||
|
SendMessage('log', payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the given debug message with the backend
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
export function Debug(message) {
|
||||||
|
sendLogMessage('debug', message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the given info message with the backend
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
export function Info(message) {
|
||||||
|
sendLogMessage('info', message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the given warning message with the backend
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
export function Warning(message) {
|
||||||
|
sendLogMessage('warning', message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the given error message with the backend
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
export function Error(message) {
|
||||||
|
sendLogMessage('error', message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the given fatal message with the backend
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
export function Fatal(message) {
|
||||||
|
sendLogMessage('fatal', message);
|
||||||
|
}
|
||||||
|
|
||||||
54
runtime/js/core/main.js
Normal file
54
runtime/js/core/main.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
import * as Log from './log';
|
||||||
|
import * as Browser from './browser';
|
||||||
|
import { On, Emit, Notify, Heartbeat, Acknowledge } from './events';
|
||||||
|
import { NewBinding } from './bindings';
|
||||||
|
import { Callback } from './calls';
|
||||||
|
import { AddScript, InjectCSS } from './utils';
|
||||||
|
|
||||||
|
// Initialise global if not already
|
||||||
|
window.wails = window.wails || {};
|
||||||
|
window.backend = {};
|
||||||
|
|
||||||
|
// Setup internal calls
|
||||||
|
var internal = {
|
||||||
|
NewBinding,
|
||||||
|
Callback,
|
||||||
|
Notify,
|
||||||
|
AddScript,
|
||||||
|
InjectCSS,
|
||||||
|
Init,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setup runtime structure
|
||||||
|
var runtime = {
|
||||||
|
Log,
|
||||||
|
Browser,
|
||||||
|
Events: {
|
||||||
|
On,
|
||||||
|
Emit,
|
||||||
|
Heartbeat,
|
||||||
|
Acknowledge,
|
||||||
|
},
|
||||||
|
_: internal,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Augment global
|
||||||
|
Object.assign(window.wails, runtime);
|
||||||
|
|
||||||
|
// Emit loaded event
|
||||||
|
Emit('wails:loaded');
|
||||||
|
|
||||||
|
// Nothing to init in production
|
||||||
|
export function Init(callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
34
runtime/js/core/utils.js
Normal file
34
runtime/js/core/utils.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
import { Emit } from './events';
|
||||||
|
|
||||||
|
export function AddScript(js, callbackID) {
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.text = js;
|
||||||
|
document.body.appendChild(script);
|
||||||
|
if (callbackID) {
|
||||||
|
Emit(callbackID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adapted from webview - thanks zserge!
|
||||||
|
export function InjectCSS(css) {
|
||||||
|
var elem = document.createElement('style');
|
||||||
|
elem.setAttribute('type', 'text/css');
|
||||||
|
if (elem.styleSheet) {
|
||||||
|
elem.styleSheet.cssText = css;
|
||||||
|
} else {
|
||||||
|
elem.appendChild(document.createTextNode(css));
|
||||||
|
}
|
||||||
|
var head = document.head || document.getElementsByTagName('head')[0];
|
||||||
|
head.appendChild(elem);
|
||||||
|
}
|
||||||
7686
runtime/js/package-lock.json
generated
Normal file
7686
runtime/js/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user