mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 22:31:06 +08:00
Develop (#343)
* Support Distribution 'ArcoLinux' #310 (#312) * Support Distribution 'ArcoLinux' #310 * Vuetify2 support (resurrected from git@github.com:MichaelHipp/wails.git) (#315) * Initial create of vuetify2-basic folder * Change template descr of vuetify-basic to say Vuetify 1.5 * Get vuetify2 template installing vuetify v2.0 (but with styling probs) * Update App.vue, HelloWorld.vue for Vuetify v2 * Remove babel-polyfill, add mdi/font * fix: codacy corrections * fix: babel -> core-js, regenerator-runtime Co-authored-by: Michael Hipp <michael@redmule.com> Co-authored-by: Lea Anthony <lea.anthony@gmail.com> * Update Contributors * v1.0.2-pre1 * [313-remote-conn] allow remote connections to the websocket bridge (#314) * [313-remote-conn] feat: compute wsURL based on window.location * [313-remote-conn] feat: allow any host to connect to vue server removing the 'host: "localhost"' specification causes the development server to listen on all interfaces. * [313-remote-conn] feat: allow any host to connect to angular dev server * test: reinject tabs Co-authored-by: Lea Anthony <lea.anthony@gmail.com> * fix: disable host check for vuetify 2 template * v1.0.2-pre2 * fix: shutdown ipcmanager * use channel to trigger shutdown * load linuxdb from relative path * Feat manjaro arm & deepin (#324) * feat: new distros: manjaroARM & Deepin * v1.0.2-pre3 * [326-platform-raspbian] feat: implement raspbian support (#327) * fix: emit arguments (#306) * v1.0.2-pre4 Raspbarian support * Initial support for Typescript decl file (#330) * v1.0.2-pre5 * revert to Go 1.12 * New CI (#331) * prepare * new CI/github actions * Rename later-pre.yml to latest-pre.yml * Update latest-pre.yml * Update README.md * Ensure version in go.mod is up to date (#339) * release v1.0.2-pre6 * Fix typescript generation * Release v1.0.2-pre7 * 316-multi-bridge-conn (#317) * [316-multi-bridge-conn] feat: use callback func for bridge response * [316-multi-bridge-conn] feat: implement multiple session support * split client handling portion into 'session' * keep track of sessions by remote address (ip & port) * notify each of the sessions anytime an event comes across the bus * [316-multi-bridge-conn] chore: move bridge files to package * [316-multi-bridge-conn] chore: remove deprecated Callback function The Callback function is no longer needed for the operation of the frontend callback since the ipc.Dispatch function now requires a callback function to be provided as an argument. This function can be a private function since it is passed by reference. * [316-multi-bridge-conn] chore: make webview.Callback private * [316-multi-bridge-conn] chore: remove unused injectCSS function I believe a slightly better method of doing this might need to be devised if it is needed in the future. I presume it should collect the values into a cache and then inject it into each sesssion as it appears. * [316-multi-bridge-conn] ensure wails:ready event is emitted Event is only emitted for the first session created from the Bridge. * [316-multi-bridge-conn] emit events for session lifecycle Emit an event for each session started and ended. * [316-multi-bridge-conn] fix: session handling fixes Co-authored-by: Lea Anthony <lea.anthony@gmail.com> * Release v1.0.2-pre8 * Release v1.0.2 Co-authored-by: Byron <ktc@protonmail.com> Co-authored-by: Travis McLane <tmclane@gmail.com> Co-authored-by: Michael Hipp <michael@redmule.com>
This commit is contained in:
parent
c506c95506
commit
79188c503f
32
.github/workflows/latest-pre.yml
vendored
Normal file
32
.github/workflows/latest-pre.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
name: latest pre-release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '**-pre**'
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Test Build Latest Pre-Release
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go 1.12
|
||||||
|
uses: actions/setup-go@v1
|
||||||
|
with:
|
||||||
|
go-version: 1.12
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Get dependencies
|
||||||
|
run: |
|
||||||
|
go get -v -d ./...
|
||||||
|
- name: Build
|
||||||
|
run: go build -v ./cmd/wails
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: ./wails version
|
32
.github/workflows/pr.yml
vendored
Normal file
32
.github/workflows/pr.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
name: pr
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Test Build PR
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go 1.12
|
||||||
|
uses: actions/setup-go@v1
|
||||||
|
with:
|
||||||
|
go-version: 1.12
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Get dependencies
|
||||||
|
run: |
|
||||||
|
go get -v -d ./...
|
||||||
|
- name: Build
|
||||||
|
run: go build -v ./cmd/wails
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: ./wails version
|
34
.github/workflows/release.yml
vendored
Normal file
34
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
name: release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
tags:
|
||||||
|
- '!**pre**'
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Test Build Latest Release
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go 1.12
|
||||||
|
uses: actions/setup-go@v1
|
||||||
|
with:
|
||||||
|
go-version: 1.12
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Get dependencies
|
||||||
|
run: |
|
||||||
|
go get -v -d ./...
|
||||||
|
- name: Build
|
||||||
|
run: go build -v ./cmd/wails
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: ./wails version
|
@ -21,3 +21,5 @@ Wails is what it is because of the time and effort given by these great people.
|
|||||||
* [Robin Eklind](https://github.com/mewmew)
|
* [Robin Eklind](https://github.com/mewmew)
|
||||||
* [Kris Raney](https://github.com/kraney)
|
* [Kris Raney](https://github.com/kraney)
|
||||||
* [Jack Mordaunt](https://github.com/JackMordaunt)
|
* [Jack Mordaunt](https://github.com/JackMordaunt)
|
||||||
|
* [Michael Hipp](https://github.com/MichaelHipp)
|
||||||
|
* [Travis McLane](https://github.com/tmclane)
|
@ -11,7 +11,8 @@
|
|||||||
<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://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://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>
|
<a href="https://github.com/wailsapp/wails/workflows/release/badge.svg?branch=master" rel="nofollow"><img src="https://github.com/wailsapp/wails/workflows/release/badge.svg?branch=master" alt="Release Pipelines"></a>
|
||||||
|
<a href="https://github.com/wailsapp/wails/workflows/latest-pre/badge.svg?branch=masterr" rel="nofollow"><img src="https://github.com/wailsapp/wails/workflows/latest-pre/badge.svg?branch=master" alt="Pre-Release 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!
|
||||||
|
2
app.go
2
app.go
@ -97,7 +97,7 @@ func (a *App) start() error {
|
|||||||
|
|
||||||
// Check if we are to run in bridge mode
|
// Check if we are to run in bridge mode
|
||||||
if BuildMode == cmd.BuildModeBridge {
|
if BuildMode == cmd.BuildModeBridge {
|
||||||
a.renderer = &renderer.Bridge{}
|
a.renderer = renderer.NewBridge()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise the renderer
|
// Initialise the renderer
|
||||||
|
@ -1,138 +0,0 @@
|
|||||||
# 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'
|
|
@ -1,138 +0,0 @@
|
|||||||
# 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'
|
|
File diff suppressed because one or more lines are too long
10
cmd/fs.go
10
cmd/fs.go
@ -132,6 +132,16 @@ func (fs *FSHelper) LocalDir(dir string) (*Dir, error) {
|
|||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadRelativeFile loads the given file relative to the caller's directory
|
||||||
|
func (fs *FSHelper) LoadRelativeFile(relativePath string) ([]byte, error) {
|
||||||
|
_, filename, _, _ := runtime.Caller(0)
|
||||||
|
fullPath, err := filepath.Abs(filepath.Join(path.Dir(filename), relativePath))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ioutil.ReadFile(fullPath)
|
||||||
|
}
|
||||||
|
|
||||||
// GetSubdirs will return a list of FQPs to subdirectories in the given directory
|
// GetSubdirs will return a list of FQPs to subdirectories in the given directory
|
||||||
func (d *Dir) GetSubdirs() (map[string]string, error) {
|
func (d *Dir) GetSubdirs() (map[string]string, error) {
|
||||||
|
|
||||||
|
78
cmd/gomod.go
Normal file
78
cmd/gomod.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/Masterminds/semver"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetWailsVersion() (*semver.Version, error) {
|
||||||
|
var FS = NewFSHelper()
|
||||||
|
var result *semver.Version
|
||||||
|
|
||||||
|
// Load file
|
||||||
|
var err error
|
||||||
|
goModFile, err := filepath.Abs(filepath.Join(".", "go.mod"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to load go.mod at %s", goModFile)
|
||||||
|
}
|
||||||
|
goMod, err := FS.LoadAsString(goModFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to load go.mod")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find wails version
|
||||||
|
versionRegexp := regexp.MustCompile(`.*github.com/wailsapp/wails.*(v\d+.\d+.\d+(?:-pre\d+)?)`)
|
||||||
|
versions := versionRegexp.FindStringSubmatch(goMod)
|
||||||
|
|
||||||
|
if len(versions) != 2 {
|
||||||
|
return nil, fmt.Errorf("Unable to determine Wails version")
|
||||||
|
}
|
||||||
|
|
||||||
|
version := versions[1]
|
||||||
|
result, err = semver.NewVersion(version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse Wails version: %s", version)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCurrentVersion() (*semver.Version, error) {
|
||||||
|
result, err := semver.NewVersion(Version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse Wails version: %s", Version)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GoModOutOfSync() (bool, error) {
|
||||||
|
gomodversion, err := GetWailsVersion()
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
currentVersion, err := GetCurrentVersion()
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
result := !currentVersion.Equal(gomodversion)
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateGoModVersion() error {
|
||||||
|
currentVersion, err := GetCurrentVersion()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
currentVersionString := currentVersion.String()
|
||||||
|
|
||||||
|
requireLine := "-require=github.com/wailsapp/wails@v" + currentVersionString
|
||||||
|
|
||||||
|
// Issue: go mod edit -require=github.com/wailsapp/wails@1.0.2-pre5
|
||||||
|
helper := NewProgramHelper()
|
||||||
|
command := []string{"go", "mod", "edit", requireLine}
|
||||||
|
return helper.RunCommandArray(command)
|
||||||
|
|
||||||
|
}
|
@ -99,8 +99,7 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
|||||||
binaryName = strings.TrimSuffix(binaryName, ".exe")
|
binaryName = strings.TrimSuffix(binaryName, ".exe")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buildCommand.Add("-o")
|
buildCommand.Add("-o", binaryName)
|
||||||
buildCommand.Add(binaryName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are forcing a rebuild
|
// If we are forcing a rebuild
|
||||||
@ -121,6 +120,16 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
|||||||
|
|
||||||
ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
|
ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
|
||||||
|
|
||||||
|
// If we wish to generate typescript
|
||||||
|
if projectOptions.typescriptDefsFilename != "" {
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
filename := filepath.Join(cwd, projectOptions.FrontEnd.Dir, projectOptions.typescriptDefsFilename)
|
||||||
|
ldflags += " -X github.com/wailsapp/wails/lib/binding.typescriptDefinitionFilename=" + filename
|
||||||
|
}
|
||||||
|
|
||||||
buildCommand.AddSlice([]string{"-ldflags", ldflags})
|
buildCommand.AddSlice([]string{"-ldflags", ldflags})
|
||||||
err = NewProgramHelper().RunCommandArray(buildCommand.AsSlice())
|
err = NewProgramHelper().RunCommandArray(buildCommand.AsSlice())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
17
cmd/linux.go
17
cmd/linux.go
@ -43,8 +43,16 @@ const (
|
|||||||
Kali
|
Kali
|
||||||
// Neon distribution
|
// Neon distribution
|
||||||
Neon
|
Neon
|
||||||
|
// ArcoLinux distribution
|
||||||
|
ArcoLinux
|
||||||
// Manjaro distribution
|
// Manjaro distribution
|
||||||
Manjaro
|
Manjaro
|
||||||
|
// ManjaroARM distribution
|
||||||
|
ManjaroARM
|
||||||
|
// Deepin distribution
|
||||||
|
Deepin
|
||||||
|
// Raspbian distribution
|
||||||
|
Raspbian
|
||||||
)
|
)
|
||||||
|
|
||||||
// DistroInfo contains all the information relating to a linux distribution
|
// DistroInfo contains all the information relating to a linux distribution
|
||||||
@ -100,6 +108,7 @@ func parseOsRelease(osRelease string) *DistroInfo {
|
|||||||
version = strings.Trim(splitLine[1], "\"")
|
version = strings.Trim(splitLine[1], "\"")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check distro name against list of distros
|
// Check distro name against list of distros
|
||||||
switch osID {
|
switch osID {
|
||||||
case "fedora":
|
case "fedora":
|
||||||
@ -128,8 +137,16 @@ func parseOsRelease(osRelease string) *DistroInfo {
|
|||||||
result.Distribution = Kali
|
result.Distribution = Kali
|
||||||
case "neon":
|
case "neon":
|
||||||
result.Distribution = Neon
|
result.Distribution = Neon
|
||||||
|
case "arcolinux":
|
||||||
|
result.Distribution = ArcoLinux
|
||||||
case "manjaro":
|
case "manjaro":
|
||||||
result.Distribution = Manjaro
|
result.Distribution = Manjaro
|
||||||
|
case "manjaro-arm":
|
||||||
|
result.Distribution = ManjaroARM
|
||||||
|
case "deepin":
|
||||||
|
result.Distribution = Deepin
|
||||||
|
case "raspbian":
|
||||||
|
result.Distribution = Raspbian
|
||||||
default:
|
default:
|
||||||
result.Distribution = Unknown
|
result.Distribution = Unknown
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/leaanthony/mewn"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -79,11 +78,14 @@ func (l *LinuxDB) GetDistro(distro string) *Distribution {
|
|||||||
// NewLinuxDB creates a new LinuxDB instance from the bundled
|
// NewLinuxDB creates a new LinuxDB instance from the bundled
|
||||||
// linuxdb.yaml file.
|
// linuxdb.yaml file.
|
||||||
func NewLinuxDB() *LinuxDB {
|
func NewLinuxDB() *LinuxDB {
|
||||||
data := mewn.Bytes("./linuxdb.yaml")
|
data, err := fs.LoadRelativeFile("./linuxdb.yaml")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Could not load linuxdb.yaml")
|
||||||
|
}
|
||||||
result := LinuxDB{
|
result := LinuxDB{
|
||||||
Distributions: make(map[string]*Distribution),
|
Distributions: make(map[string]*Distribution),
|
||||||
}
|
}
|
||||||
err := result.ImportData(data)
|
err = result.ImportData(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,15 @@ distributions:
|
|||||||
gccversioncommand: *gccdumpfullversion
|
gccversioncommand: *gccdumpfullversion
|
||||||
programs: *debiandefaultprograms
|
programs: *debiandefaultprograms
|
||||||
libraries: *debiandefaultlibraries
|
libraries: *debiandefaultlibraries
|
||||||
|
deepin:
|
||||||
|
id: deepin
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Deepin
|
||||||
|
gccversioncommand: *gccdumpfullversion
|
||||||
|
programs: *debiandefaultprograms
|
||||||
|
libraries: *debiandefaultlibraries
|
||||||
void:
|
void:
|
||||||
id: void
|
id: void
|
||||||
releases:
|
releases:
|
||||||
@ -158,6 +167,15 @@ distributions:
|
|||||||
help: Please install with `sudo pacman -S gtk3` and try again
|
help: Please install with `sudo pacman -S gtk3` and try again
|
||||||
- name: webkit2gtk
|
- name: webkit2gtk
|
||||||
help: Please install with `sudo pacman -S webkit2gtk` and try again
|
help: Please install with `sudo pacman -S webkit2gtk` and try again
|
||||||
|
arcolinux:
|
||||||
|
id: arcolinux
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: ArcoLinux
|
||||||
|
gccversioncommand: *gccdumpversion
|
||||||
|
programs: *archdefaultprograms
|
||||||
|
libraries: *archdefaultlibraries
|
||||||
manjaro:
|
manjaro:
|
||||||
id: manjaro
|
id: manjaro
|
||||||
releases:
|
releases:
|
||||||
@ -167,6 +185,15 @@ distributions:
|
|||||||
gccversioncommand: *gccdumpversion
|
gccversioncommand: *gccdumpversion
|
||||||
programs: *archdefaultprograms
|
programs: *archdefaultprograms
|
||||||
libraries: *archdefaultlibraries
|
libraries: *archdefaultlibraries
|
||||||
|
manjaro-arm:
|
||||||
|
id: manjaro-arm
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Manjaro-ARM
|
||||||
|
gccversioncommand: *gccdumpversion
|
||||||
|
programs: *archdefaultprograms
|
||||||
|
libraries: *archdefaultlibraries
|
||||||
gentoo:
|
gentoo:
|
||||||
id: gentoo
|
id: gentoo
|
||||||
releases:
|
releases:
|
||||||
@ -185,4 +212,14 @@ distributions:
|
|||||||
- name: gtk+:3
|
- name: gtk+:3
|
||||||
help: Please install with `sudo emerge gtk+:3` and try again
|
help: Please install with `sudo emerge gtk+:3` and try again
|
||||||
- name: webkit-gtk
|
- name: webkit-gtk
|
||||||
help: Please install with `sudo emerge webkit-gtk` and try again
|
help: Please install with `sudo emerge webkit-gtk` and try again
|
||||||
|
|
||||||
|
raspbian:
|
||||||
|
id: raspbian
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Raspbian
|
||||||
|
gccversioncommand: *gccdumpfullversion
|
||||||
|
programs: *debiandefaultprograms
|
||||||
|
libraries: *debiandefaultlibraries
|
||||||
|
@ -142,21 +142,22 @@ func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions {
|
|||||||
|
|
||||||
// ProjectOptions holds all the options available for a project
|
// ProjectOptions holds all the options available for a project
|
||||||
type ProjectOptions struct {
|
type ProjectOptions struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Author *author `json:"author,omitempty"`
|
Author *author `json:"author,omitempty"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
OutputDirectory string `json:"-"`
|
OutputDirectory string `json:"-"`
|
||||||
UseDefaults bool `json:"-"`
|
UseDefaults bool `json:"-"`
|
||||||
Template string `json:"-"`
|
Template string `json:"-"`
|
||||||
BinaryName string `json:"binaryname"`
|
BinaryName string `json:"binaryname"`
|
||||||
FrontEnd *frontend `json:"frontend,omitempty"`
|
FrontEnd *frontend `json:"frontend,omitempty"`
|
||||||
NPMProjectName string `json:"-"`
|
NPMProjectName string `json:"-"`
|
||||||
system *SystemHelper
|
system *SystemHelper
|
||||||
log *Logger
|
log *Logger
|
||||||
templates *TemplateHelper
|
templates *TemplateHelper
|
||||||
selectedTemplate *TemplateDetails
|
selectedTemplate *TemplateDetails
|
||||||
WailsVersion string
|
WailsVersion string
|
||||||
|
typescriptDefsFilename string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defaults sets the default project template
|
// Defaults sets the default project template
|
||||||
@ -165,6 +166,11 @@ func (po *ProjectOptions) Defaults() {
|
|||||||
po.WailsVersion = Version
|
po.WailsVersion = Version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetTypescriptDefsFilename indicates that we want to generate typescript bindings to the given file
|
||||||
|
func (po *ProjectOptions) SetTypescriptDefsFilename(filename string) {
|
||||||
|
po.typescriptDefsFilename = filename
|
||||||
|
}
|
||||||
|
|
||||||
// GetNPMBinaryName returns the type of package manager used by the project
|
// GetNPMBinaryName returns the type of package manager used by the project
|
||||||
func (po *ProjectOptions) GetNPMBinaryName() (PackageManager, error) {
|
func (po *ProjectOptions) GetNPMBinaryName() (PackageManager, error) {
|
||||||
if po.FrontEnd == nil {
|
if po.FrontEnd == nil {
|
||||||
|
@ -274,9 +274,9 @@ func CheckDependencies(logger *Logger) (bool, error) {
|
|||||||
distroInfo := GetLinuxDistroInfo()
|
distroInfo := GetLinuxDistroInfo()
|
||||||
|
|
||||||
switch distroInfo.Distribution {
|
switch distroInfo.Distribution {
|
||||||
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon:
|
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon, Deepin, Raspbian:
|
||||||
libraryChecker = DpkgInstalled
|
libraryChecker = DpkgInstalled
|
||||||
case Arch, Manjaro:
|
case Arch, ArcoLinux, Manjaro, ManjaroARM:
|
||||||
libraryChecker = PacmanInstalled
|
libraryChecker = PacmanInstalled
|
||||||
case CentOS, Fedora:
|
case CentOS, Fedora:
|
||||||
libraryChecker = RpmInstalled
|
libraryChecker = RpmInstalled
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "npx ng",
|
"ng": "npx ng",
|
||||||
"start": "npx ng serve --poll=2000",
|
"start": "npx ng serve --poll=2000 --host=0.0.0.0",
|
||||||
"build": "npx ng build --single-bundle true --output-hashing none --prod --bundle-styles false",
|
"build": "npx ng build --single-bundle true --output-hashing none --prod --bundle-styles false",
|
||||||
"test": "npx ng test",
|
"test": "npx ng test",
|
||||||
"lint": "npx ng lint",
|
"lint": "npx ng lint",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
'@vue/app'
|
[ '@vue/app', { useBuiltIns: 'entry' } ]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^2.6.4",
|
"core-js": "^3.6.1",
|
||||||
|
"regenerator-runtime": "^0.13.3",
|
||||||
"vue": "^2.5.22",
|
"vue": "^2.5.22",
|
||||||
"@wailsapp/runtime": "^1.0.0"
|
"@wailsapp/runtime": "^1.0.0"
|
||||||
},
|
},
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'core-js/stable';
|
||||||
|
import 'regenerator-runtime/runtime';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
disableHostCheck: true,
|
disableHostCheck: true
|
||||||
host: "localhost"
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
'@vue/app'
|
[ '@vue/app', { useBuiltIns: 'entry' } ]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"babel-polyfill": "^6.26.0",
|
"core-js": "^3.6.1",
|
||||||
"core-js": "^2.6.4",
|
"regenerator-runtime": "^0.13.3",
|
||||||
"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",
|
||||||
@ -50,4 +50,4 @@
|
|||||||
"last 2 versions",
|
"last 2 versions",
|
||||||
"not ie <= 8"
|
"not ie <= 8"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'babel-polyfill';
|
import 'core-js/stable';
|
||||||
|
import 'regenerator-runtime/runtime';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
|
||||||
// Setup Vuetify
|
// Setup Vuetify
|
||||||
|
@ -37,7 +37,6 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
disableHostCheck: true,
|
disableHostCheck: true
|
||||||
host: "localhost"
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "Vuetify Basic",
|
"name": "Vuetify1.5/Webpack Basic",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"shortdescription": "Vuetify + Webpack",
|
"shortdescription": "A basic Vuetify1.5/Webpack4 template",
|
||||||
"description": "Basic template using Vuetify and bundled using Webpack",
|
"description": "Basic template using Vuetify v1.5 and bundled using Webpack",
|
||||||
"install": "npm install",
|
"install": "npm install",
|
||||||
"build": "npm run build",
|
"build": "npm run build",
|
||||||
"author": "lea <lea.anthony@gmail.com>",
|
"author": "lea <lea.anthony@gmail.com>",
|
||||||
@ -11,4 +11,4 @@
|
|||||||
"serve": "npm run serve",
|
"serve": "npm run serve",
|
||||||
"bridge": "src",
|
"bridge": "src",
|
||||||
"wailsdir": ""
|
"wailsdir": ""
|
||||||
}
|
}
|
||||||
|
3
cmd/templates/vuetify2-basic/.jshint
Normal file
3
cmd/templates/vuetify2-basic/.jshint
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"esversion": 6
|
||||||
|
}
|
21
cmd/templates/vuetify2-basic/frontend/.gitignore
vendored
Normal file
21
cmd/templates/vuetify2-basic/frontend/.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw*
|
5
cmd/templates/vuetify2-basic/frontend/babel.config.js
Normal file
5
cmd/templates/vuetify2-basic/frontend/babel.config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
[ '@vue/app', { useBuiltIns: 'entry' } ]
|
||||||
|
]
|
||||||
|
};
|
53
cmd/templates/vuetify2-basic/frontend/package.json.template
Normal file
53
cmd/templates/vuetify2-basic/frontend/package.json.template
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"name": "{{.NPMProjectName}}",
|
||||||
|
"author": "{{.Author.Name}}<{{.Author.Email}}>",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"core-js": "^3.6.1",
|
||||||
|
"regenerator-runtime": "^0.13.3",
|
||||||
|
"vue": "^2.5.22",
|
||||||
|
"vuetify": "^2.0.15",
|
||||||
|
"@wailsapp/runtime": "^1.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@mdi/font": "^4.3.95",
|
||||||
|
"@vue/cli-plugin-babel": "^3.4.0",
|
||||||
|
"@vue/cli-plugin-eslint": "^3.4.0",
|
||||||
|
"@vue/cli-service": "^3.4.0",
|
||||||
|
"babel-eslint": "^10.0.1",
|
||||||
|
"eslint": "^5.8.0",
|
||||||
|
"eslint-plugin-vue": "^5.0.0",
|
||||||
|
"eventsource-polyfill": "^0.9.6",
|
||||||
|
"vue-template-compiler": "^2.5.21",
|
||||||
|
"webpack-hot-middleware": "^2.24.3"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"rules": {},
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"postcss": {
|
||||||
|
"plugins": {
|
||||||
|
"autoprefixer": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not ie <= 8"
|
||||||
|
]
|
||||||
|
}
|
60
cmd/templates/vuetify2-basic/frontend/src/App.vue
Normal file
60
cmd/templates/vuetify2-basic/frontend/src/App.vue
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<v-app id="inspire">
|
||||||
|
<v-navigation-drawer v-model="drawer" clipped fixed app>
|
||||||
|
<v-list dense>
|
||||||
|
<v-list-item>
|
||||||
|
<v-list-item-icon>
|
||||||
|
<v-icon>mdi-view-dashboard</v-icon>
|
||||||
|
</v-list-item-icon>
|
||||||
|
<v-list-item-content>
|
||||||
|
<v-list-item-title>Dashboard</v-list-item-title>
|
||||||
|
</v-list-item-content>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item>
|
||||||
|
<v-list-item-icon>
|
||||||
|
<v-icon>mdi-settings</v-icon>
|
||||||
|
</v-list-item-icon>
|
||||||
|
<v-list-item-content>
|
||||||
|
<v-list-item-title>Settings</v-list-item-title>
|
||||||
|
</v-list-item-content>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-navigation-drawer>
|
||||||
|
<v-app-bar app fixed clipped-left>
|
||||||
|
<v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
|
||||||
|
<v-toolbar-title>Application</v-toolbar-title>
|
||||||
|
</v-app-bar>
|
||||||
|
<v-content>
|
||||||
|
<v-container fluid class="px-0">
|
||||||
|
<v-layout justify-center align-center class="px-0">
|
||||||
|
<hello-world></hello-world>
|
||||||
|
</v-layout>
|
||||||
|
</v-container>
|
||||||
|
</v-content>
|
||||||
|
<v-footer app fixed>
|
||||||
|
<span style="margin-left:1em">© You</span>
|
||||||
|
</v-footer>
|
||||||
|
</v-app>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import HelloWorld from "./components/HelloWorld.vue"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data: () => ({
|
||||||
|
drawer: false
|
||||||
|
}),
|
||||||
|
components: {
|
||||||
|
HelloWorld
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
source: String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.logo {
|
||||||
|
width: 16em;
|
||||||
|
}
|
||||||
|
</style>
|
BIN
cmd/templates/vuetify2-basic/frontend/src/assets/images/logo.png
Normal file
BIN
cmd/templates/vuetify2-basic/frontend/src/assets/images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 301 KiB |
@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<v-container fluid class="px-0">
|
||||||
|
<v-layout>
|
||||||
|
<v-flex xs12 sm6 offset-sm3>
|
||||||
|
<v-card raised="raised" class="pa-4 ma-4">
|
||||||
|
<v-layout justify-center align-center class="pa-4 ma-4">
|
||||||
|
<v-img :src="require('../assets/images/logo.png')"></v-img>
|
||||||
|
</v-layout>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-layout justify-center align-center class="px-0">
|
||||||
|
<v-btn color="blue" @click="getMessage">Press Me</v-btn>
|
||||||
|
</v-layout>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-flex>
|
||||||
|
</v-layout>
|
||||||
|
<div class="text-xs-center">
|
||||||
|
<v-dialog v-model="dialog" width="500">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title class="headline" primary-title>Message from Go</v-card-title>
|
||||||
|
<v-card-text>{{message}}</v-card-text>
|
||||||
|
<v-divider></v-divider>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn color="primary" text @click="dialog = false">Awesome</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</div>
|
||||||
|
</v-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
message: " ",
|
||||||
|
raised: true,
|
||||||
|
dialog: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getMessage: function () {
|
||||||
|
var self = this
|
||||||
|
window.backend.basic().then(result => {
|
||||||
|
self.message = result
|
||||||
|
self.dialog = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
h1 {
|
||||||
|
margin-top: 2em;
|
||||||
|
position: relative;
|
||||||
|
min-height: 5rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
font-size: 1.7em;
|
||||||
|
border-color: blue;
|
||||||
|
background-color: blue;
|
||||||
|
color: white;
|
||||||
|
border: 3px solid white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 9px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: 500ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-size: 1.7em;
|
||||||
|
border-color: white;
|
||||||
|
background-color: #121212;
|
||||||
|
color: white;
|
||||||
|
border: 3px solid white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 9px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
29
cmd/templates/vuetify2-basic/frontend/src/main.js
Normal file
29
cmd/templates/vuetify2-basic/frontend/src/main.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import 'core-js/stable';
|
||||||
|
import 'regenerator-runtime/runtime';
|
||||||
|
import '@mdi/font/css/materialdesignicons.css';
|
||||||
|
import Vue from 'vue';
|
||||||
|
import Vuetify from 'vuetify';
|
||||||
|
import 'vuetify/dist/vuetify.min.css';
|
||||||
|
|
||||||
|
Vue.use(Vuetify);
|
||||||
|
|
||||||
|
import App from './App.vue';
|
||||||
|
|
||||||
|
Vue.config.productionTip = false;
|
||||||
|
Vue.config.devtools = true;
|
||||||
|
|
||||||
|
import Wails from '@wailsapp/runtime';
|
||||||
|
|
||||||
|
Wails.Init(() => {
|
||||||
|
new Vue({
|
||||||
|
vuetify: new Vuetify({
|
||||||
|
icons: {
|
||||||
|
iconfont: 'mdi'
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
dark: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
render: h => h(App)
|
||||||
|
}).$mount('#app');
|
||||||
|
});
|
42
cmd/templates/vuetify2-basic/frontend/vue.config.js
Normal file
42
cmd/templates/vuetify2-basic/frontend/vue.config.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
let cssConfig = {};
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV == 'production') {
|
||||||
|
cssConfig = {
|
||||||
|
extract: {
|
||||||
|
filename: '[name].css',
|
||||||
|
chunkFilename: '[name].css'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
chainWebpack: config => {
|
||||||
|
let limit = 9999999999999999;
|
||||||
|
config.module
|
||||||
|
.rule('images')
|
||||||
|
.test(/\.(png|gif|jpg)(\?.*)?$/i)
|
||||||
|
.use('url-loader')
|
||||||
|
.loader('url-loader')
|
||||||
|
.tap(options => Object.assign(options, { limit: limit }));
|
||||||
|
config.module
|
||||||
|
.rule('fonts')
|
||||||
|
.test(/\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/i)
|
||||||
|
.use('url-loader')
|
||||||
|
.loader('url-loader')
|
||||||
|
.options({
|
||||||
|
limit: limit
|
||||||
|
});
|
||||||
|
},
|
||||||
|
css: cssConfig,
|
||||||
|
configureWebpack: {
|
||||||
|
output: {
|
||||||
|
filename: '[name].js'
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
splitChunks: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
disableHostCheck: true
|
||||||
|
}
|
||||||
|
};
|
5
cmd/templates/vuetify2-basic/go.mod.template
Normal file
5
cmd/templates/vuetify2-basic/go.mod.template
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module {{.BinaryName}}
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/wailsapp/wails {{.WailsVersion}}
|
||||||
|
)
|
27
cmd/templates/vuetify2-basic/main.go.template
Normal file
27
cmd/templates/vuetify2-basic/main.go.template
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/leaanthony/mewn"
|
||||||
|
"github.com/wailsapp/wails"
|
||||||
|
)
|
||||||
|
|
||||||
|
func basic() string {
|
||||||
|
return "Hello World!"
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
js := mewn.String("./frontend/dist/app.js")
|
||||||
|
css := mewn.String("./frontend/dist/app.css")
|
||||||
|
|
||||||
|
app := wails.CreateApp(&wails.AppConfig{
|
||||||
|
Width: 1024,
|
||||||
|
Height: 768,
|
||||||
|
Title: "{{.Name}}",
|
||||||
|
JS: js,
|
||||||
|
CSS: css,
|
||||||
|
Colour: "#131313",
|
||||||
|
})
|
||||||
|
app.Bind(basic)
|
||||||
|
app.Run()
|
||||||
|
}
|
14
cmd/templates/vuetify2-basic/template.json
Executable file
14
cmd/templates/vuetify2-basic/template.json
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "Vuetify2/Webpack Basic",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"shortdescription": "A basic Vuetify2/Webpack4 template",
|
||||||
|
"description": "Basic template using Vuetify v2 and bundled using Webpack",
|
||||||
|
"install": "npm install",
|
||||||
|
"build": "npm run build",
|
||||||
|
"author": "Michael Hipp <michael@redmule.com>",
|
||||||
|
"created": "2019-09-06",
|
||||||
|
"frontenddir": "frontend",
|
||||||
|
"serve": "npm run serve",
|
||||||
|
"bridge": "src",
|
||||||
|
"wailsdir": ""
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
// Version - Wails version
|
// Version - Wails version
|
||||||
const Version = "v1.0.1"
|
const Version = "v1.0.2"
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Masterminds/semver"
|
"github.com/Masterminds/semver"
|
||||||
@ -183,35 +182,13 @@ func checkProjectDirectory() error {
|
|||||||
|
|
||||||
func getWailsVersion() (*semver.Version, error) {
|
func getWailsVersion() (*semver.Version, error) {
|
||||||
checkSpinner.Start("Get Wails Version")
|
checkSpinner.Start("Get Wails Version")
|
||||||
var result *semver.Version
|
|
||||||
|
|
||||||
// Load file
|
result, err := cmd.GetWailsVersion()
|
||||||
var err error
|
|
||||||
goModFile, err = filepath.Abs(filepath.Join(".", "go.mod"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
checkSpinner.Error()
|
checkSpinner.Error(err.Error())
|
||||||
return nil, fmt.Errorf("Unable to load go.mod at %s", goModFile)
|
return nil, err
|
||||||
}
|
}
|
||||||
goMod, err = migrateFS.LoadAsString(goModFile)
|
|
||||||
if err != nil {
|
|
||||||
checkSpinner.Error()
|
|
||||||
return nil, fmt.Errorf("Unable to load go.mod")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find wails version
|
|
||||||
versionRegexp := regexp.MustCompile(`.*github.com/wailsapp/wails.*(v\d+.\d+.\d+)`)
|
|
||||||
versions := versionRegexp.FindStringSubmatch(goMod)
|
|
||||||
|
|
||||||
if len(versions) != 2 {
|
|
||||||
return nil, fmt.Errorf("Unable to determine Wails version")
|
|
||||||
}
|
|
||||||
|
|
||||||
version := versions[1]
|
|
||||||
result, err = semver.NewVersion(version)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Unable to parse Wails version: %s", version)
|
|
||||||
}
|
|
||||||
checkSpinner.Success("Found Wails Version: " + version)
|
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ func init() {
|
|||||||
var packageApp = false
|
var packageApp = false
|
||||||
var forceRebuild = false
|
var forceRebuild = false
|
||||||
var debugMode = false
|
var debugMode = false
|
||||||
|
var typescriptFilename = ""
|
||||||
|
|
||||||
buildSpinner := spinner.NewSpinner()
|
buildSpinner := spinner.NewSpinner()
|
||||||
buildSpinner.SetSpinSpeed(50)
|
buildSpinner.SetSpinSpeed(50)
|
||||||
|
|
||||||
@ -21,7 +23,8 @@ func init() {
|
|||||||
LongDescription(commandDescription).
|
LongDescription(commandDescription).
|
||||||
BoolFlag("p", "Package application on successful build", &packageApp).
|
BoolFlag("p", "Package application on successful build", &packageApp).
|
||||||
BoolFlag("f", "Force rebuild of application components", &forceRebuild).
|
BoolFlag("f", "Force rebuild of application components", &forceRebuild).
|
||||||
BoolFlag("d", "Build in Debug mode", &debugMode)
|
BoolFlag("d", "Build in Debug mode", &debugMode).
|
||||||
|
StringFlag("t", "Generate Typescript definitions to given file (at runtime)", &typescriptFilename)
|
||||||
|
|
||||||
initCmd.Action(func() error {
|
initCmd.Action(func() error {
|
||||||
|
|
||||||
@ -73,16 +76,13 @@ func init() {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that runtime init.js is the production version
|
// Ensure that runtime init.js is the production version
|
||||||
err = cmd.InstallProdRuntime(projectDir, projectOptions)
|
err = cmd.InstallProdRuntime(projectDir, projectOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Move to project directory
|
// Move to project directory
|
||||||
err = os.Chdir(projectDir)
|
err = os.Chdir(projectDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -101,6 +101,32 @@ func init() {
|
|||||||
buildMode = cmd.BuildModeDebug
|
buildMode = cmd.BuildModeDebug
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save if we wish to dump typescript or not
|
||||||
|
if typescriptFilename != "" {
|
||||||
|
projectOptions.SetTypescriptDefsFilename(typescriptFilename)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update go.mod if it is out of sync with current version
|
||||||
|
outofsync, err := cmd.GoModOutOfSync()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
gomodVersion, err := cmd.GetWailsVersion()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if outofsync {
|
||||||
|
syncMessage := fmt.Sprintf("Updating go.mod (Wails version %s => %s)", gomodVersion, cmd.Version)
|
||||||
|
buildSpinner := spinner.NewSpinner(syncMessage)
|
||||||
|
buildSpinner.Start()
|
||||||
|
err := cmd.UpdateGoModVersion()
|
||||||
|
if err != nil {
|
||||||
|
buildSpinner.Error(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buildSpinner.Success()
|
||||||
|
}
|
||||||
|
|
||||||
err = cmd.BuildApplication(projectOptions.BinaryName, forceRebuild, buildMode, packageApp, projectOptions)
|
err = cmd.BuildApplication(projectOptions.BinaryName, forceRebuild, buildMode, packageApp, projectOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
4
go.mod
4
go.mod
@ -13,7 +13,7 @@ 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.2
|
github.com/leaanthony/slicer v1.4.0
|
||||||
github.com/leaanthony/spinner v0.5.3
|
github.com/leaanthony/spinner v0.5.3
|
||||||
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
|
||||||
@ -31,3 +31,5 @@ require (
|
|||||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4
|
gopkg.in/AlecAivazis/survey.v1 v1.8.4
|
||||||
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
|
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
|
||||||
)
|
)
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
2
go.sum
2
go.sum
@ -36,6 +36,8 @@ github.com/leaanthony/mewn v0.10.7 h1:jCcNJyIUOpwj+I5SuATvCugDjHkoo+j6ubEOxxrxmP
|
|||||||
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.2 h1:kGWWFoyaY5WzwGrUsHXMmGbssuYthP4qYBNlkNpNAB8=
|
github.com/leaanthony/slicer v1.3.2 h1:kGWWFoyaY5WzwGrUsHXMmGbssuYthP4qYBNlkNpNAB8=
|
||||||
github.com/leaanthony/slicer v1.3.2/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
|
github.com/leaanthony/slicer v1.3.2/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
|
||||||
|
github.com/leaanthony/slicer v1.4.0 h1:Q9u4w+UBU4WHjXnEDdz+eRLMKF/rnyosRBiqULnc1J8=
|
||||||
|
github.com/leaanthony/slicer v1.4.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||||
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=
|
||||||
|
@ -2,7 +2,11 @@ package binding
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/lib/interfaces"
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
@ -10,6 +14,8 @@ import (
|
|||||||
"github.com/wailsapp/wails/lib/messages"
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var typescriptDefinitionFilename = ""
|
||||||
|
|
||||||
// Manager handles method binding
|
// Manager handles method binding
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
methods map[string]*boundMethod
|
methods map[string]*boundMethod
|
||||||
@ -21,16 +27,19 @@ type Manager struct {
|
|||||||
renderer interfaces.Renderer
|
renderer interfaces.Renderer
|
||||||
runtime interfaces.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
|
||||||
|
structList map[string][]string // structList["mystruct"] = []string{"Method1", "Method2"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager creates a new Manager struct
|
// NewManager creates a new Manager struct
|
||||||
func NewManager() interfaces.BindingManager {
|
func NewManager() interfaces.BindingManager {
|
||||||
|
|
||||||
result := &Manager{
|
result := &Manager{
|
||||||
methods: make(map[string]*boundMethod),
|
methods: make(map[string]*boundMethod),
|
||||||
functions: make(map[string]*boundFunction),
|
functions: make(map[string]*boundFunction),
|
||||||
log: logger.NewCustomLogger("Bind"),
|
log: logger.NewCustomLogger("Bind"),
|
||||||
internalMethods: newInternalMethods(),
|
internalMethods: newInternalMethods(),
|
||||||
|
structList: make(map[string][]string),
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -88,9 +97,55 @@ func (b *Manager) initialise() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we wish to generate a typescript definition file...
|
||||||
|
if typescriptDefinitionFilename != "" {
|
||||||
|
err := b.generateTypescriptDefinitions()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate typescript
|
||||||
|
func (b *Manager) generateTypescriptDefinitions() error {
|
||||||
|
|
||||||
|
var output strings.Builder
|
||||||
|
|
||||||
|
for structname, methodList := range b.structList {
|
||||||
|
structname = strings.SplitN(structname, ".", 2)[1]
|
||||||
|
output.WriteString(fmt.Sprintf("Interface %s {\n", structname))
|
||||||
|
for _, method := range methodList {
|
||||||
|
output.WriteString(fmt.Sprintf("\t%s: (...args : any[]) => Promise\n", method))
|
||||||
|
}
|
||||||
|
output.WriteString("}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
output.WriteString("\n")
|
||||||
|
output.WriteString("Interface Backend {\n")
|
||||||
|
|
||||||
|
for structname := range b.structList {
|
||||||
|
structname = strings.SplitN(structname, ".", 2)[1]
|
||||||
|
output.WriteString(fmt.Sprintf("\t%[1]s: %[1]s\n", structname))
|
||||||
|
}
|
||||||
|
output.WriteString("}\n")
|
||||||
|
|
||||||
|
globals := `
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
backend: Backend;
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
output.WriteString(globals)
|
||||||
|
|
||||||
|
b.log.Info("Written Typescript file: " + typescriptDefinitionFilename)
|
||||||
|
|
||||||
|
dir := filepath.Dir(typescriptDefinitionFilename)
|
||||||
|
os.MkdirAll(dir, 0755)
|
||||||
|
return ioutil.WriteFile(typescriptDefinitionFilename, []byte(output.String()), 0755)
|
||||||
|
}
|
||||||
|
|
||||||
// bind the given struct method
|
// bind the given struct method
|
||||||
func (b *Manager) bindMethod(object interface{}) error {
|
func (b *Manager) bindMethod(object interface{}) error {
|
||||||
|
|
||||||
@ -104,6 +159,12 @@ func (b *Manager) bindMethod(object interface{}) error {
|
|||||||
|
|
||||||
b.log.Debugf("Processing struct: %s", baseName)
|
b.log.Debugf("Processing struct: %s", baseName)
|
||||||
|
|
||||||
|
// Calc actual name
|
||||||
|
actualName := strings.TrimPrefix(baseName, "main.")
|
||||||
|
if b.structList[actualName] == nil {
|
||||||
|
b.structList[actualName] = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over method definitions
|
// Iterate over method definitions
|
||||||
for i := 0; i < objectType.NumMethod(); i++ {
|
for i := 0; i < objectType.NumMethod(); i++ {
|
||||||
|
|
||||||
@ -113,6 +174,8 @@ func (b *Manager) bindMethod(object interface{}) error {
|
|||||||
fullMethodName := baseName + "." + methodName
|
fullMethodName := baseName + "." + methodName
|
||||||
method := reflect.ValueOf(object).MethodByName(methodName)
|
method := reflect.ValueOf(object).MethodByName(methodName)
|
||||||
|
|
||||||
|
b.structList[actualName] = append(b.structList[actualName], methodName)
|
||||||
|
|
||||||
// Skip unexported methods
|
// Skip unexported methods
|
||||||
if !unicode.IsUpper([]rune(methodName)[0]) {
|
if !unicode.IsUpper([]rune(methodName)[0]) {
|
||||||
continue
|
continue
|
||||||
|
@ -3,7 +3,6 @@ package event
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/lib/interfaces"
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
"github.com/wailsapp/wails/lib/logger"
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
@ -13,6 +12,7 @@ import (
|
|||||||
// Manager handles and processes events
|
// Manager handles and processes events
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
incomingEvents chan *messages.EventData
|
incomingEvents chan *messages.EventData
|
||||||
|
quitChannel chan struct{}
|
||||||
listeners map[string][]*eventListener
|
listeners map[string][]*eventListener
|
||||||
running bool
|
running bool
|
||||||
log *logger.CustomLogger
|
log *logger.CustomLogger
|
||||||
@ -24,6 +24,7 @@ type Manager struct {
|
|||||||
func NewManager() interfaces.EventManager {
|
func NewManager() interfaces.EventManager {
|
||||||
return &Manager{
|
return &Manager{
|
||||||
incomingEvents: make(chan *messages.EventData, 100),
|
incomingEvents: make(chan *messages.EventData, 100),
|
||||||
|
quitChannel: make(chan struct{}, 1),
|
||||||
listeners: make(map[string][]*eventListener),
|
listeners: make(map[string][]*eventListener),
|
||||||
running: false,
|
running: false,
|
||||||
log: logger.NewCustomLogger("Events"),
|
log: logger.NewCustomLogger("Events"),
|
||||||
@ -141,8 +142,8 @@ func (e *Manager) Start(renderer interfaces.Renderer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
case <-e.quitChannel:
|
||||||
time.Sleep(1 * time.Millisecond)
|
e.running = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e.wg.Done()
|
e.wg.Done()
|
||||||
@ -152,7 +153,7 @@ func (e *Manager) Start(renderer interfaces.Renderer) {
|
|||||||
// Shutdown is called when exiting the Application
|
// Shutdown is called when exiting the Application
|
||||||
func (e *Manager) Shutdown() {
|
func (e *Manager) Shutdown() {
|
||||||
e.log.Debug("Shutting Down")
|
e.log.Debug("Shutting Down")
|
||||||
e.running = false
|
e.quitChannel <- struct{}{}
|
||||||
e.log.Debug("Waiting for main loop to exit")
|
e.log.Debug("Waiting for main loop to exit")
|
||||||
e.wg.Wait()
|
e.wg.Wait()
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package interfaces
|
package interfaces
|
||||||
|
|
||||||
|
// CallbackFunc defines the signature of a function required to be provided to the
|
||||||
|
// Dispatch function so that the response may be returned
|
||||||
|
type CallbackFunc func(string) error
|
||||||
|
|
||||||
// IPCManager is the event manager interface
|
// IPCManager is the event manager interface
|
||||||
type IPCManager interface {
|
type IPCManager interface {
|
||||||
BindRenderer(Renderer)
|
BindRenderer(Renderer)
|
||||||
Dispatch(message string)
|
Dispatch(message string, f CallbackFunc)
|
||||||
Start(eventManager EventManager, bindingManager BindingManager)
|
Start(eventManager EventManager, bindingManager BindingManager)
|
||||||
Shutdown()
|
Shutdown()
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ type Renderer interface {
|
|||||||
|
|
||||||
// Binding
|
// Binding
|
||||||
NewBinding(bindingName string) error
|
NewBinding(bindingName string) error
|
||||||
Callback(data string) error
|
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
NotifyEvent(eventData *messages.EventData) error
|
NotifyEvent(eventData *messages.EventData) error
|
||||||
|
@ -3,7 +3,6 @@ package ipc
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/lib/interfaces"
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
"github.com/wailsapp/wails/lib/logger"
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
@ -124,8 +123,8 @@ func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager int
|
|||||||
i.log.DebugFields("Finished processing message", logger.Fields{
|
i.log.DebugFields("Finished processing message", logger.Fields{
|
||||||
"1D": &incomingMessage,
|
"1D": &incomingMessage,
|
||||||
})
|
})
|
||||||
default:
|
case <-i.quitChannel:
|
||||||
time.Sleep(1 * time.Millisecond)
|
i.running = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i.log.Debug("Stopping")
|
i.log.Debug("Stopping")
|
||||||
@ -136,10 +135,10 @@ func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager int
|
|||||||
// 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 *Manager) Dispatch(message string) {
|
func (i *Manager) Dispatch(message string, cb interfaces.CallbackFunc) {
|
||||||
|
|
||||||
// Create a new IPC Message
|
// Create a new IPC Message
|
||||||
incomingMessage, err := newIPCMessage(message, i.SendResponse)
|
incomingMessage, err := newIPCMessage(message, i.SendResponse(cb))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i.log.ErrorFields("Could not understand incoming message! ", map[string]interface{}{
|
i.log.ErrorFields("Could not understand incoming message! ", map[string]interface{}{
|
||||||
"message": message,
|
"message": message,
|
||||||
@ -159,23 +158,25 @@ func (i *Manager) Dispatch(message string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SendResponse sends the given response back to the frontend
|
// SendResponse sends the given response back to the frontend
|
||||||
func (i *Manager) SendResponse(response *ipcResponse) error {
|
// It sends the data back to the correct renderer by way of the provided callback function
|
||||||
|
func (i *Manager) SendResponse(cb interfaces.CallbackFunc) func(i *ipcResponse) error {
|
||||||
|
|
||||||
// Serialise the Message
|
return func(response *ipcResponse) error {
|
||||||
data, err := response.Serialise()
|
// Serialise the Message
|
||||||
if err != nil {
|
data, err := response.Serialise()
|
||||||
fmt.Printf(err.Error())
|
if err != nil {
|
||||||
return err
|
fmt.Printf(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return cb(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call back to the front end
|
|
||||||
return i.renderer.Callback(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown is called when exiting the Application
|
// Shutdown is called when exiting the Application
|
||||||
func (i *Manager) Shutdown() {
|
func (i *Manager) Shutdown() {
|
||||||
i.log.Debug("Shutdown called")
|
i.log.Debug("Shutdown called")
|
||||||
i.running = false
|
i.quitChannel <- struct{}{}
|
||||||
i.log.Debug("Waiting of main loop shutdown")
|
i.log.Debug("Waiting of main loop shutdown")
|
||||||
i.wg.Wait()
|
i.wg.Wait()
|
||||||
}
|
}
|
||||||
|
@ -1,262 +1,10 @@
|
|||||||
package renderer
|
package renderer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
bridge "github.com/wailsapp/wails/lib/renderer/bridge"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/dchest/htmlmin"
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
"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
|
// NewBridge returns a new Bridge struct
|
||||||
|
func NewBridge() *bridge.Bridge {
|
||||||
const (
|
return &bridge.Bridge{}
|
||||||
jsMessage messageType = iota
|
|
||||||
cssMessage
|
|
||||||
htmlMessage
|
|
||||||
notifyMessage
|
|
||||||
bindingMessage
|
|
||||||
callbackMessage
|
|
||||||
wailsRuntimeMessage
|
|
||||||
)
|
|
||||||
|
|
||||||
func (m messageType) toString() string {
|
|
||||||
return [...]string{"j", "s", "h", "n", "b", "c", "w"}[m]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bridge is a backend that opens a local web server
|
|
||||||
// and renders the files over a websocket
|
|
||||||
type Bridge struct {
|
|
||||||
// Common
|
|
||||||
log *logger.CustomLogger
|
|
||||||
ipcManager interfaces.IPCManager
|
|
||||||
appConfig interfaces.AppConfig
|
|
||||||
eventManager interfaces.EventManager
|
|
||||||
bindingCache []string
|
|
||||||
|
|
||||||
// Bridge specific
|
|
||||||
initialisationJS []string
|
|
||||||
server *http.Server
|
|
||||||
theConnection *websocket.Conn
|
|
||||||
|
|
||||||
// Mutex for writing to the socket
|
|
||||||
lock sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialise the Bridge Renderer
|
|
||||||
func (h *Bridge) Initialise(appConfig interfaces.AppConfig, ipcManager interfaces.IPCManager, eventManager interfaces.EventManager) error {
|
|
||||||
h.ipcManager = ipcManager
|
|
||||||
h.appConfig = appConfig
|
|
||||||
h.eventManager = eventManager
|
|
||||||
ipcManager.BindRenderer(h)
|
|
||||||
h.log = logger.NewCustomLogger("Bridge")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Bridge) evalJS(js string, mtype messageType) error {
|
|
||||||
|
|
||||||
message := mtype.toString() + js
|
|
||||||
|
|
||||||
if h.theConnection == nil {
|
|
||||||
h.initialisationJS = append(h.initialisationJS, message)
|
|
||||||
} else {
|
|
||||||
// Prepend message type to message
|
|
||||||
h.sendMessage(h.theConnection, message)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnableConsole not needed for bridge!
|
|
||||||
func (h *Bridge) EnableConsole() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Bridge) injectCSS(css string) {
|
|
||||||
// Minify css to overcome issues in the browser with carriage returns
|
|
||||||
minified, err := htmlmin.Minify([]byte(css), &htmlmin.Options{
|
|
||||||
MinifyStyles: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
h.log.Fatal("Unable to minify CSS: " + css)
|
|
||||||
}
|
|
||||||
minifiedCSS := string(minified)
|
|
||||||
minifiedCSS = strings.Replace(minifiedCSS, "\\", "\\\\", -1)
|
|
||||||
minifiedCSS = strings.Replace(minifiedCSS, "'", "\\'", -1)
|
|
||||||
minifiedCSS = strings.Replace(minifiedCSS, "\n", " ", -1)
|
|
||||||
inject := fmt.Sprintf("wails._.InjectCSS('%s')", minifiedCSS)
|
|
||||||
h.evalJS(inject, cssMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Bridge) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
h.theConnection = conn
|
|
||||||
h.log.Infof("Connection from frontend accepted [%p].", h.theConnection)
|
|
||||||
conn.SetCloseHandler(func(int, string) error {
|
|
||||||
h.log.Infof("Connection dropped [%p].", h.theConnection)
|
|
||||||
h.theConnection = nil
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
go h.start(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Bridge) sendMessage(conn *websocket.Conn, msg string) {
|
|
||||||
|
|
||||||
h.lock.Lock()
|
|
||||||
defer h.lock.Unlock()
|
|
||||||
|
|
||||||
if err := conn.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil {
|
|
||||||
h.log.Error(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Bridge) start(conn *websocket.Conn) {
|
|
||||||
|
|
||||||
// set external.invoke
|
|
||||||
h.log.Infof("Connected to frontend.")
|
|
||||||
|
|
||||||
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
|
||||||
h.evalJS(wailsRuntime, wailsRuntimeMessage)
|
|
||||||
|
|
||||||
// Inject bindings
|
|
||||||
for _, binding := range h.bindingCache {
|
|
||||||
h.evalJS(binding, bindingMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit that everything is loaded and ready
|
|
||||||
h.eventManager.Emit("wails:ready")
|
|
||||||
|
|
||||||
for {
|
|
||||||
messageType, buffer, err := conn.ReadMessage()
|
|
||||||
if messageType == -1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
h.log.Errorf("Error reading message: ", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
h.log.Debugf("Got message: %#v\n", string(buffer))
|
|
||||||
|
|
||||||
h.ipcManager.Dispatch(string(buffer))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the app in Bridge mode!
|
|
||||||
func (h *Bridge) Run() error {
|
|
||||||
h.server = &http.Server{Addr: ":34115"}
|
|
||||||
http.HandleFunc("/bridge", h.wsBridgeHandler)
|
|
||||||
|
|
||||||
h.log.Info("Bridge mode started.")
|
|
||||||
h.log.Info("The frontend will connect automatically.")
|
|
||||||
|
|
||||||
err := h.server.ListenAndServe()
|
|
||||||
if err != nil && err != http.ErrServerClosed {
|
|
||||||
h.log.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBinding creates a new binding with the frontend
|
|
||||||
func (h *Bridge) NewBinding(methodName string) error {
|
|
||||||
h.bindingCache = append(h.bindingCache, methodName)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectFile is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) SelectFile() string {
|
|
||||||
h.log.Warn("SelectFile() unsupported in bridge mode")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectDirectory is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) SelectDirectory() string {
|
|
||||||
h.log.Warn("SelectDirectory() unsupported in bridge mode")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectSaveFile is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) SelectSaveFile() string {
|
|
||||||
h.log.Warn("SelectSaveFile() unsupported in bridge mode")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callback sends a callback to the frontend
|
|
||||||
func (h *Bridge) Callback(data string) error {
|
|
||||||
return h.evalJS(data, callbackMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotifyEvent notifies the frontend of an event
|
|
||||||
func (h *Bridge) NotifyEvent(event *messages.EventData) error {
|
|
||||||
|
|
||||||
// Look out! Nils about!
|
|
||||||
var err error
|
|
||||||
if event == nil {
|
|
||||||
err = fmt.Errorf("Sent nil event to renderer.webViewRenderer")
|
|
||||||
h.log.Error(err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default data is a blank array
|
|
||||||
data := []byte("[]")
|
|
||||||
|
|
||||||
// Process event data
|
|
||||||
if event.Data != nil {
|
|
||||||
// Marshall the data
|
|
||||||
data, err = json.Marshal(event.Data)
|
|
||||||
if err != nil {
|
|
||||||
h.log.Errorf("Cannot unmarshall JSON data in event: %s ", err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message := fmt.Sprintf("window.wails._.Notify('%s','%s')", event.Name, data)
|
|
||||||
return h.evalJS(message, notifyMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetColour is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) SetColour(colour string) error {
|
|
||||||
h.log.WarnFields("SetColour ignored for Bridge more", logger.Fields{"col": colour})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fullscreen is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) Fullscreen() {
|
|
||||||
h.log.Warn("Fullscreen() unsupported in bridge mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnFullscreen is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) UnFullscreen() {
|
|
||||||
h.log.Warn("UnFullscreen() unsupported in bridge mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTitle is currently unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) SetTitle(title string) {
|
|
||||||
h.log.WarnFields("SetTitle() unsupported in bridge mode", logger.Fields{"title": title})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) Close() {
|
|
||||||
h.log.Debug("Shutting down")
|
|
||||||
err := h.server.Close()
|
|
||||||
if err != nil {
|
|
||||||
h.log.Errorf(err.Error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
214
lib/renderer/bridge/bridge.go
Normal file
214
lib/renderer/bridge/bridge.go
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
package renderer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
|
)
|
||||||
|
|
||||||
|
type messageType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
jsMessage messageType = iota
|
||||||
|
cssMessage
|
||||||
|
htmlMessage
|
||||||
|
notifyMessage
|
||||||
|
bindingMessage
|
||||||
|
callbackMessage
|
||||||
|
wailsRuntimeMessage
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m messageType) toString() string {
|
||||||
|
return [...]string{"j", "s", "h", "n", "b", "c", "w"}[m]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bridge is a backend that opens a local web server
|
||||||
|
// and renders the files over a websocket
|
||||||
|
type Bridge struct {
|
||||||
|
// Common
|
||||||
|
log *logger.CustomLogger
|
||||||
|
ipcManager interfaces.IPCManager
|
||||||
|
appConfig interfaces.AppConfig
|
||||||
|
eventManager interfaces.EventManager
|
||||||
|
bindingCache []string
|
||||||
|
|
||||||
|
// Bridge specific
|
||||||
|
server *http.Server
|
||||||
|
|
||||||
|
lock sync.Mutex
|
||||||
|
sessions map[string]session
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise the Bridge Renderer
|
||||||
|
func (h *Bridge) Initialise(appConfig interfaces.AppConfig, ipcManager interfaces.IPCManager, eventManager interfaces.EventManager) error {
|
||||||
|
h.sessions = map[string]session{}
|
||||||
|
h.ipcManager = ipcManager
|
||||||
|
h.appConfig = appConfig
|
||||||
|
h.eventManager = eventManager
|
||||||
|
ipcManager.BindRenderer(h)
|
||||||
|
h.log = logger.NewCustomLogger("Bridge")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableConsole not needed for bridge!
|
||||||
|
func (h *Bridge) EnableConsole() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Bridge) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
h.log.Infof("Connection from frontend accepted [%s].", conn.RemoteAddr().String())
|
||||||
|
h.startSession(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Bridge) startSession(conn *websocket.Conn) {
|
||||||
|
s := session{
|
||||||
|
conn: conn,
|
||||||
|
bindingCache: h.bindingCache,
|
||||||
|
ipc: h.ipcManager,
|
||||||
|
log: h.log,
|
||||||
|
eventManager: h.eventManager,
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.SetCloseHandler(func(int, string) error {
|
||||||
|
h.log.Infof("Connection dropped [%s].", s.Identifier())
|
||||||
|
h.eventManager.Emit("wails:bridge:session:closed", s.Identifier())
|
||||||
|
h.lock.Lock()
|
||||||
|
defer h.lock.Unlock()
|
||||||
|
delete(h.sessions, s.Identifier())
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
h.lock.Lock()
|
||||||
|
defer h.lock.Unlock()
|
||||||
|
go s.start(len(h.sessions) == 0)
|
||||||
|
h.sessions[s.Identifier()] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the app in Bridge mode!
|
||||||
|
func (h *Bridge) Run() error {
|
||||||
|
h.server = &http.Server{Addr: ":34115"}
|
||||||
|
http.HandleFunc("/bridge", h.wsBridgeHandler)
|
||||||
|
|
||||||
|
h.log.Info("Bridge mode started.")
|
||||||
|
h.log.Info("The frontend will connect automatically.")
|
||||||
|
|
||||||
|
err := h.server.ListenAndServe()
|
||||||
|
if err != nil && err != http.ErrServerClosed {
|
||||||
|
h.log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBinding creates a new binding with the frontend
|
||||||
|
func (h *Bridge) NewBinding(methodName string) error {
|
||||||
|
h.bindingCache = append(h.bindingCache, methodName)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectFile is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) SelectFile() string {
|
||||||
|
h.log.Warn("SelectFile() unsupported in bridge mode")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDirectory is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) SelectDirectory() string {
|
||||||
|
h.log.Warn("SelectDirectory() unsupported in bridge mode")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectSaveFile is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) SelectSaveFile() string {
|
||||||
|
h.log.Warn("SelectSaveFile() unsupported in bridge mode")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifyEvent notifies the frontend of an event
|
||||||
|
func (h *Bridge) NotifyEvent(event *messages.EventData) error {
|
||||||
|
|
||||||
|
// Look out! Nils about!
|
||||||
|
var err error
|
||||||
|
if event == nil {
|
||||||
|
err = fmt.Errorf("Sent nil event to renderer.webViewRenderer")
|
||||||
|
h.log.Error(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default data is a blank array
|
||||||
|
data := []byte("[]")
|
||||||
|
|
||||||
|
// Process event data
|
||||||
|
if event.Data != nil {
|
||||||
|
// Marshall the data
|
||||||
|
data, err = json.Marshal(event.Data)
|
||||||
|
if err != nil {
|
||||||
|
h.log.Errorf("Cannot unmarshall JSON data in event: %s ", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message := fmt.Sprintf("window.wails._.Notify('%s','%s')", event.Name, data)
|
||||||
|
dead := []session{}
|
||||||
|
for _, session := range h.sessions {
|
||||||
|
err := session.evalJS(message, notifyMessage)
|
||||||
|
if err != nil {
|
||||||
|
h.log.Debugf("Failed to send message to %s - Removing listener : %v", session.Identifier(), err)
|
||||||
|
h.log.Infof("Connection from [%v] unresponsive - dropping", session.Identifier())
|
||||||
|
dead = append(dead, session)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.lock.Lock()
|
||||||
|
defer h.lock.Unlock()
|
||||||
|
for _, session := range dead {
|
||||||
|
delete(h.sessions, session.Identifier())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetColour is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) SetColour(colour string) error {
|
||||||
|
h.log.WarnFields("SetColour ignored for Bridge more", logger.Fields{"col": colour})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fullscreen is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) Fullscreen() {
|
||||||
|
h.log.Warn("Fullscreen() unsupported in bridge mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnFullscreen is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) UnFullscreen() {
|
||||||
|
h.log.Warn("UnFullscreen() unsupported in bridge mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTitle is currently unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) SetTitle(title string) {
|
||||||
|
h.log.WarnFields("SetTitle() unsupported in bridge mode", logger.Fields{"title": title})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) Close() {
|
||||||
|
h.log.Debug("Shutting down")
|
||||||
|
err := h.server.Close()
|
||||||
|
if err != nil {
|
||||||
|
h.log.Errorf(err.Error())
|
||||||
|
}
|
||||||
|
}
|
90
lib/renderer/bridge/session.go
Normal file
90
lib/renderer/bridge/session.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package renderer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/leaanthony/mewn"
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO Move this back into bridge.go
|
||||||
|
|
||||||
|
// session represents a single websocket session
|
||||||
|
type session struct {
|
||||||
|
bindingCache []string
|
||||||
|
conn *websocket.Conn
|
||||||
|
eventManager interfaces.EventManager
|
||||||
|
log *logger.CustomLogger
|
||||||
|
ipc interfaces.IPCManager
|
||||||
|
|
||||||
|
// Mutex for writing to the socket
|
||||||
|
lock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identifier returns a string identifier for the remote connection.
|
||||||
|
// Taking the form of the client's <ip address>:<port>.
|
||||||
|
func (s *session) Identifier() string {
|
||||||
|
if s.conn != nil {
|
||||||
|
return s.conn.RemoteAddr().String()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *session) sendMessage(msg string) error {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
if err := s.conn.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil {
|
||||||
|
s.log.Debug(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *session) start(firstSession bool) {
|
||||||
|
s.log.Infof("Connected to frontend.")
|
||||||
|
|
||||||
|
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
||||||
|
s.evalJS(wailsRuntime, wailsRuntimeMessage)
|
||||||
|
|
||||||
|
// Inject bindings
|
||||||
|
for _, binding := range s.bindingCache {
|
||||||
|
s.evalJS(binding, bindingMessage)
|
||||||
|
}
|
||||||
|
s.eventManager.Emit("wails:bridge:session:started", s.Identifier())
|
||||||
|
|
||||||
|
// Emit that everything is loaded and ready
|
||||||
|
if firstSession {
|
||||||
|
s.eventManager.Emit("wails:ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
messageType, buffer, err := s.conn.ReadMessage()
|
||||||
|
if messageType == -1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
s.log.Errorf("Error reading message: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s.log.Debugf("Got message: %#v\n", string(buffer))
|
||||||
|
|
||||||
|
s.ipc.Dispatch(string(buffer), s.Callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback sends a callback to the frontend
|
||||||
|
func (s *session) Callback(data string) error {
|
||||||
|
return s.evalJS(data, callbackMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *session) evalJS(js string, mtype messageType) error {
|
||||||
|
|
||||||
|
// Prepend message type to message
|
||||||
|
return s.sendMessage(mtype.toString() + js)
|
||||||
|
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -58,7 +58,7 @@ func (w *WebView) Initialise(config interfaces.AppConfig, ipc interfaces.IPCMana
|
|||||||
URL: config.GetDefaultHTML(),
|
URL: config.GetDefaultHTML(),
|
||||||
Debug: !config.GetDisableInspector(),
|
Debug: !config.GetDisableInspector(),
|
||||||
ExternalInvokeCallback: func(_ wv.WebView, message string) {
|
ExternalInvokeCallback: func(_ wv.WebView, message string) {
|
||||||
w.ipc.Dispatch(message)
|
w.ipc.Dispatch(message, w.callback)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -299,8 +299,8 @@ func (w *WebView) SelectSaveFile() string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback sends a callback to the frontend
|
// callback sends a callback to the frontend
|
||||||
func (w *WebView) 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)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ function init() {
|
|||||||
window.wailsbridge = {
|
window.wailsbridge = {
|
||||||
reconnectOverlay: null,
|
reconnectOverlay: null,
|
||||||
reconnectTimer: 300,
|
reconnectTimer: 300,
|
||||||
wsURL: 'ws://localhost:34115/bridge',
|
wsURL: 'ws://' + window.location.hostname + ':34115/bridge',
|
||||||
connectionState: null,
|
connectionState: null,
|
||||||
config: {},
|
config: {},
|
||||||
websocket: null,
|
websocket: null,
|
||||||
|
File diff suppressed because one or more lines are too long
@ -52,7 +52,8 @@ function Once(eventName, callback) {
|
|||||||
* @param {string} eventName
|
* @param {string} eventName
|
||||||
*/
|
*/
|
||||||
function Emit(eventName) {
|
function Emit(eventName) {
|
||||||
return window.wails.Events.Emit(eventName);
|
var args = [eventName].slice.call(arguments);
|
||||||
|
return window.wails.Events.Emit.apply(null, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,4 +18,4 @@ function Init(callback) {
|
|||||||
window.wails._.Init(callback);
|
window.wails._.Init(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Init;
|
module.exports = Init;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wailsapp/runtime",
|
"name": "@wailsapp/runtime",
|
||||||
"version": "1.0.9",
|
"version": "1.0.10",
|
||||||
"description": "Wails Javascript runtime library",
|
"description": "Wails Javascript runtime library",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"types": "runtime.d.ts",
|
"types": "runtime.d.ts",
|
||||||
|
Loading…
Reference in New Issue
Block a user