5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-03 06:51:26 +08:00
wails/lib/ipc/manager.go
Lea Anthony 79188c503f
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>
2020-02-08 09:58:16 +11:00

183 lines
4.9 KiB
Go

package ipc
import (
"fmt"
"sync"
"github.com/wailsapp/wails/lib/interfaces"
"github.com/wailsapp/wails/lib/logger"
"github.com/wailsapp/wails/lib/messages"
)
// Manager manages the IPC subsystem
type Manager struct {
renderer interfaces.Renderer // The renderer
messageQueue chan *ipcMessage
quitChannel chan struct{}
// signals chan os.Signal
log *logger.CustomLogger
eventManager interfaces.EventManager
bindingManager interfaces.BindingManager
running bool
wg sync.WaitGroup
}
// NewManager creates a new IPC Manager
func NewManager() interfaces.IPCManager {
result := &Manager{
messageQueue: make(chan *ipcMessage, 100),
quitChannel: make(chan struct{}),
// signals: make(chan os.Signal, 1),
log: logger.NewCustomLogger("IPC"),
}
return result
}
// BindRenderer sets the renderer, returns the dispatch function
func (i *Manager) BindRenderer(renderer interfaces.Renderer) {
i.renderer = renderer
}
// Start the IPC Manager
func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager interfaces.BindingManager) {
// Store manager references
i.eventManager = eventManager
i.bindingManager = bindingManager
i.log.Info("Starting")
// signal.Notify(manager.signals, os.Interrupt)
i.running = true
// Keep track of this goroutine
i.wg.Add(1)
go func() {
for i.running {
select {
case incomingMessage := <-i.messageQueue:
i.log.DebugFields("Processing message", logger.Fields{
"1D": &incomingMessage,
})
switch incomingMessage.Type {
case "call":
callData := incomingMessage.Payload.(*messages.CallData)
i.log.DebugFields("Processing call", logger.Fields{
"1D": &incomingMessage,
"bindingName": callData.BindingName,
"data": callData.Data,
})
go func() {
result, err := bindingManager.ProcessCall(callData)
i.log.DebugFields("processed call", logger.Fields{"result": result, "err": err})
if err != nil {
incomingMessage.ReturnError(err.Error())
} else {
incomingMessage.ReturnSuccess(result)
}
i.log.DebugFields("Finished processing call", logger.Fields{
"1D": &incomingMessage,
})
}()
case "event":
// Extract event data
eventData := incomingMessage.Payload.(*messages.EventData)
// Log
i.log.DebugFields("Processing event", logger.Fields{
"name": eventData.Name,
"data": eventData.Data,
})
// Push the event to the event manager
i.eventManager.PushEvent(eventData)
// Log
i.log.DebugFields("Finished processing event", logger.Fields{
"name": eventData.Name,
})
case "log":
logdata := incomingMessage.Payload.(*messages.LogData)
switch logdata.Level {
case "info":
logger.GlobalLogger.Info(logdata.Message)
case "debug":
logger.GlobalLogger.Debug(logdata.Message)
case "warning":
logger.GlobalLogger.Warn(logdata.Message)
case "error":
logger.GlobalLogger.Error(logdata.Message)
case "fatal":
logger.GlobalLogger.Fatal(logdata.Message)
default:
logger.ErrorFields("Invalid log level sent", logger.Fields{
"level": logdata.Level,
"message": logdata.Message,
})
}
default:
i.log.Debugf("bad message sent to MessageQueue! Unknown type: %s", incomingMessage.Type)
}
// Log
i.log.DebugFields("Finished processing message", logger.Fields{
"1D": &incomingMessage,
})
case <-i.quitChannel:
i.running = false
}
}
i.log.Debug("Stopping")
i.wg.Done()
}()
}
// Dispatch receives JSON encoded messages from the renderer.
// It processes the message to ensure that it is valid and places
// the processed message on the message queue
func (i *Manager) Dispatch(message string, cb interfaces.CallbackFunc) {
// Create a new IPC Message
incomingMessage, err := newIPCMessage(message, i.SendResponse(cb))
if err != nil {
i.log.ErrorFields("Could not understand incoming message! ", map[string]interface{}{
"message": message,
"error": err,
})
return
}
// Put message on queue
i.log.DebugFields("Message received", map[string]interface{}{
"type": incomingMessage.Type,
"payload": incomingMessage.Payload,
})
// Put incoming message on the message queue
i.messageQueue <- incomingMessage
}
// SendResponse sends the given response back to the frontend
// 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 {
return func(response *ipcResponse) error {
// Serialise the Message
data, err := response.Serialise()
if err != nil {
fmt.Printf(err.Error())
return err
}
return cb(data)
}
}
// Shutdown is called when exiting the Application
func (i *Manager) Shutdown() {
i.log.Debug("Shutdown called")
i.quitChannel <- struct{}{}
i.log.Debug("Waiting of main loop shutdown")
i.wg.Wait()
}