mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-04 19:39:59 +08:00

* 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>
160 lines
4.2 KiB
Go
160 lines
4.2 KiB
Go
package event
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/wailsapp/wails/lib/interfaces"
|
|
"github.com/wailsapp/wails/lib/logger"
|
|
"github.com/wailsapp/wails/lib/messages"
|
|
)
|
|
|
|
// Manager handles and processes events
|
|
type Manager struct {
|
|
incomingEvents chan *messages.EventData
|
|
quitChannel chan struct{}
|
|
listeners map[string][]*eventListener
|
|
running bool
|
|
log *logger.CustomLogger
|
|
renderer interfaces.Renderer // Messages will be dispatched to the frontend
|
|
wg sync.WaitGroup
|
|
}
|
|
|
|
// NewManager creates a new event manager with a 100 event buffer
|
|
func NewManager() interfaces.EventManager {
|
|
return &Manager{
|
|
incomingEvents: make(chan *messages.EventData, 100),
|
|
quitChannel: make(chan struct{}, 1),
|
|
listeners: make(map[string][]*eventListener),
|
|
running: false,
|
|
log: logger.NewCustomLogger("Events"),
|
|
}
|
|
}
|
|
|
|
// PushEvent places the given event on to the event queue
|
|
func (e *Manager) PushEvent(eventData *messages.EventData) {
|
|
e.incomingEvents <- eventData
|
|
}
|
|
|
|
// eventListener holds a callback function which is invoked when
|
|
// the event listened for is emitted. It has a counter which indicates
|
|
// how the total number of events it is interested in. A value of zero
|
|
// means it does not expire (default).
|
|
type eventListener struct {
|
|
callback func(...interface{}) // Function to call with emitted event data
|
|
counter int // Expire after counter callbacks. 0 = infinite
|
|
expired bool // Indicates if the listener has expired
|
|
}
|
|
|
|
// Creates a new event listener from the given callback function
|
|
func (e *Manager) addEventListener(eventName string, callback func(...interface{}), counter int) error {
|
|
|
|
// Sanity check inputs
|
|
if callback == nil {
|
|
return fmt.Errorf("nil callback bassed to addEventListener")
|
|
}
|
|
|
|
// Check event has been registered before
|
|
if e.listeners[eventName] == nil {
|
|
e.listeners[eventName] = []*eventListener{}
|
|
}
|
|
|
|
// Create the callback
|
|
listener := &eventListener{
|
|
callback: callback,
|
|
counter: counter,
|
|
}
|
|
|
|
// Register listener
|
|
e.listeners[eventName] = append(e.listeners[eventName], listener)
|
|
|
|
// All good mate
|
|
return nil
|
|
}
|
|
|
|
// On adds a listener for the given event
|
|
func (e *Manager) On(eventName string, callback func(...interface{})) {
|
|
// Add a persistent eventListener (counter = 0)
|
|
e.addEventListener(eventName, callback, 0)
|
|
}
|
|
|
|
// Emit broadcasts the given event to the subscribed listeners
|
|
func (e *Manager) Emit(eventName string, optionalData ...interface{}) {
|
|
e.incomingEvents <- &messages.EventData{Name: eventName, Data: optionalData}
|
|
}
|
|
|
|
// Start the event manager's queue processing
|
|
func (e *Manager) Start(renderer interfaces.Renderer) {
|
|
|
|
e.log.Info("Starting")
|
|
|
|
// Store renderer
|
|
e.renderer = renderer
|
|
|
|
// Set up waitgroup so we can wait for goroutine to quit
|
|
e.running = true
|
|
e.wg.Add(1)
|
|
|
|
// Run main loop in separate goroutine
|
|
go func() {
|
|
e.log.Info("Listening")
|
|
for e.running {
|
|
// TODO: Listen for application exit
|
|
select {
|
|
case event := <-e.incomingEvents:
|
|
e.log.DebugFields("Got Event", logger.Fields{
|
|
"data": event.Data,
|
|
"name": event.Name,
|
|
})
|
|
|
|
// Notify renderer
|
|
e.renderer.NotifyEvent(event)
|
|
|
|
// Notify Go listeners
|
|
var listenersToRemove []*eventListener
|
|
|
|
// Iterate listeners
|
|
for _, listener := range e.listeners[event.Name] {
|
|
|
|
// Call listener, perhaps with data
|
|
if event.Data == nil {
|
|
go listener.callback()
|
|
} else {
|
|
unpacked := event.Data.([]interface{})
|
|
go listener.callback(unpacked...)
|
|
}
|
|
|
|
// Update listen counter
|
|
if listener.counter > 0 {
|
|
listener.counter = listener.counter - 1
|
|
if listener.counter == 0 {
|
|
listener.expired = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove expired listeners in place
|
|
if len(listenersToRemove) > 0 {
|
|
listeners := e.listeners[event.Name][:0]
|
|
for _, listener := range listeners {
|
|
if !listener.expired {
|
|
listeners = append(listeners, listener)
|
|
}
|
|
}
|
|
}
|
|
case <-e.quitChannel:
|
|
e.running = false
|
|
}
|
|
}
|
|
e.wg.Done()
|
|
}()
|
|
}
|
|
|
|
// Shutdown is called when exiting the Application
|
|
func (e *Manager) Shutdown() {
|
|
e.log.Debug("Shutting Down")
|
|
e.quitChannel <- struct{}{}
|
|
e.log.Debug("Waiting for main loop to exit")
|
|
e.wg.Wait()
|
|
}
|