mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 22:13:36 +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>
215 lines
5.4 KiB
Go
215 lines
5.4 KiB
Go
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())
|
|
}
|
|
}
|