forked from mbk-lab/rui_orig
Updated wasmBridge
This commit is contained in:
parent
4e363d03a5
commit
c0f60e7bdd
34
appServer.go
34
appServer.go
|
@ -78,8 +78,8 @@ func (app *application) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
io.WriteString(w, app.getStartPage())
|
io.WriteString(w, app.getStartPage())
|
||||||
|
|
||||||
case "/ws":
|
case "/ws":
|
||||||
if brige := CreateSocketBrige(w, req); brige != nil {
|
if bridge := CreateSocketBridge(w, req); bridge != nil {
|
||||||
go app.socketReader(brige)
|
go app.socketReader(bridge)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -96,12 +96,12 @@ func (app *application) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) socketReader(brige webBrige) {
|
func (app *application) socketReader(bridge webBridge) {
|
||||||
var session Session
|
var session Session
|
||||||
events := make(chan DataObject, 1024)
|
events := make(chan DataObject, 1024)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
message, ok := brige.readMessage()
|
message, ok := bridge.readMessage()
|
||||||
if !ok {
|
if !ok {
|
||||||
events <- NewDataObject("disconnect")
|
events <- NewDataObject("disconnect")
|
||||||
return
|
return
|
||||||
|
@ -116,28 +116,28 @@ func (app *application) socketReader(brige webBrige) {
|
||||||
switch command {
|
switch command {
|
||||||
case "startSession":
|
case "startSession":
|
||||||
answer := ""
|
answer := ""
|
||||||
if session, answer = app.startSession(obj, events, brige); session != nil {
|
if session, answer = app.startSession(obj, events, bridge); session != nil {
|
||||||
if !brige.writeMessage(answer) {
|
if !bridge.writeMessage(answer) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session.onStart()
|
session.onStart()
|
||||||
go sessionEventHandler(session, events, brige)
|
go sessionEventHandler(session, events, bridge)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "reconnect":
|
case "reconnect":
|
||||||
if sessionText, ok := obj.PropertyValue("session"); ok {
|
if sessionText, ok := obj.PropertyValue("session"); ok {
|
||||||
if sessionID, err := strconv.Atoi(sessionText); err == nil {
|
if sessionID, err := strconv.Atoi(sessionText); err == nil {
|
||||||
if session = app.sessions[sessionID]; session != nil {
|
if session = app.sessions[sessionID]; session != nil {
|
||||||
session.setBrige(events, brige)
|
session.setBridge(events, bridge)
|
||||||
answer := allocStringBuilder()
|
answer := allocStringBuilder()
|
||||||
defer freeStringBuilder(answer)
|
defer freeStringBuilder(answer)
|
||||||
|
|
||||||
session.writeInitScript(answer)
|
session.writeInitScript(answer)
|
||||||
if !brige.writeMessage(answer.String()) {
|
if !bridge.writeMessage(answer.String()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session.onReconnect()
|
session.onReconnect()
|
||||||
go sessionEventHandler(session, events, brige)
|
go sessionEventHandler(session, events, bridge)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
DebugLogF("Session #%d not exists", sessionID)
|
DebugLogF("Session #%d not exists", sessionID)
|
||||||
|
@ -149,12 +149,12 @@ func (app *application) socketReader(brige webBrige) {
|
||||||
}
|
}
|
||||||
|
|
||||||
answer := ""
|
answer := ""
|
||||||
if session, answer = app.startSession(obj, events, brige); session != nil {
|
if session, answer = app.startSession(obj, events, bridge); session != nil {
|
||||||
if !brige.writeMessage(answer) {
|
if !bridge.writeMessage(answer) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session.onStart()
|
session.onStart()
|
||||||
go sessionEventHandler(session, events, brige)
|
go sessionEventHandler(session, events, bridge)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "answer":
|
case "answer":
|
||||||
|
@ -173,7 +173,7 @@ func (app *application) socketReader(brige webBrige) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sessionEventHandler(session Session, events chan DataObject, brige webBrige) {
|
func sessionEventHandler(session Session, events chan DataObject, bridge webBridge) {
|
||||||
for {
|
for {
|
||||||
data := <-events
|
data := <-events
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ func sessionEventHandler(session Session, events chan DataObject, brige webBrige
|
||||||
case "session-close":
|
case "session-close":
|
||||||
session.onFinish()
|
session.onFinish()
|
||||||
session.App().removeSession(session.ID())
|
session.App().removeSession(session.ID())
|
||||||
brige.close()
|
bridge.close()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
session.handleEvent(command, data)
|
session.handleEvent(command, data)
|
||||||
|
@ -193,13 +193,13 @@ func sessionEventHandler(session Session, events chan DataObject, brige webBrige
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) startSession(params DataObject, events chan DataObject, brige webBrige) (Session, string) {
|
func (app *application) startSession(params DataObject, events chan DataObject, bridge webBridge) (Session, string) {
|
||||||
if app.createContentFunc == nil {
|
if app.createContentFunc == nil {
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
session := newSession(app, app.nextSessionID(), "", params)
|
session := newSession(app, app.nextSessionID(), "", params)
|
||||||
session.setBrige(events, brige)
|
session.setBridge(events, bridge)
|
||||||
if !session.setContent(app.createContentFunc(session)) {
|
if !session.setContent(app.createContentFunc(session)) {
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
28
appWasm.go
28
appWasm.go
|
@ -17,7 +17,7 @@ type wasmApp struct {
|
||||||
params AppParams
|
params AppParams
|
||||||
createContentFunc func(Session) SessionContent
|
createContentFunc func(Session) SessionContent
|
||||||
session Session
|
session Session
|
||||||
brige webBrige
|
bridge webBridge
|
||||||
close chan DataObject
|
close chan DataObject
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,28 +36,28 @@ func (app *wasmApp) handleMessage(this js.Value, args []js.Value) any {
|
||||||
/*
|
/*
|
||||||
case "startSession":
|
case "startSession":
|
||||||
answer := ""
|
answer := ""
|
||||||
if session, answer = app.startSession(obj, events, brige); session != nil {
|
if session, answer = app.startSession(obj, events, bridge); session != nil {
|
||||||
if !brige.writeMessage(answer) {
|
if !bridge.writeMessage(answer) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session.onStart()
|
session.onStart()
|
||||||
go sessionEventHandler(session, events, brige)
|
go sessionEventHandler(session, events, bridge)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "reconnect":
|
case "reconnect":
|
||||||
if sessionText, ok := obj.PropertyValue("session"); ok {
|
if sessionText, ok := obj.PropertyValue("session"); ok {
|
||||||
if sessionID, err := strconv.Atoi(sessionText); err == nil {
|
if sessionID, err := strconv.Atoi(sessionText); err == nil {
|
||||||
if session = app.sessions[sessionID]; session != nil {
|
if session = app.sessions[sessionID]; session != nil {
|
||||||
session.setBrige(events, brige)
|
session.setBridge(events, bridge)
|
||||||
answer := allocStringBuilder()
|
answer := allocStringBuilder()
|
||||||
defer freeStringBuilder(answer)
|
defer freeStringBuilder(answer)
|
||||||
|
|
||||||
session.writeInitScript(answer)
|
session.writeInitScript(answer)
|
||||||
if !brige.writeMessage(answer.String()) {
|
if !bridge.writeMessage(answer.String()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session.onReconnect()
|
session.onReconnect()
|
||||||
go sessionEventHandler(session, events, brige)
|
go sessionEventHandler(session, events, bridge)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
DebugLogF("Session #%d not exists", sessionID)
|
DebugLogF("Session #%d not exists", sessionID)
|
||||||
|
@ -69,12 +69,12 @@ func (app *wasmApp) handleMessage(this js.Value, args []js.Value) any {
|
||||||
}
|
}
|
||||||
|
|
||||||
answer := ""
|
answer := ""
|
||||||
if session, answer = app.startSession(obj, events, brige); session != nil {
|
if session, answer = app.startSession(obj, events, bridge); session != nil {
|
||||||
if !brige.writeMessage(answer) {
|
if !bridge.writeMessage(answer) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session.onStart()
|
session.onStart()
|
||||||
go sessionEventHandler(session, events, brige)
|
go sessionEventHandler(session, events, bridge)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "disconnect":
|
case "disconnect":
|
||||||
|
@ -84,7 +84,7 @@ func (app *wasmApp) handleMessage(this js.Value, args []js.Value) any {
|
||||||
case "session-close":
|
case "session-close":
|
||||||
session.onFinish()
|
session.onFinish()
|
||||||
session.App().removeSession(session.ID())
|
session.App().removeSession(session.ID())
|
||||||
brige.close()
|
bridge.close()
|
||||||
|
|
||||||
*/
|
*/
|
||||||
case "answer":
|
case "answer":
|
||||||
|
@ -109,7 +109,7 @@ func (app *wasmApp) removeSession(id int) {
|
||||||
|
|
||||||
func (app *wasmApp) createSession() Session {
|
func (app *wasmApp) createSession() Session {
|
||||||
session := newSession(app, 0, "", ParseDataText(js.Global().Call("sessionInfo", "").String()))
|
session := newSession(app, 0, "", ParseDataText(js.Global().Call("sessionInfo", "").String()))
|
||||||
session.setBrige(app.close, app.brige)
|
session.setBridge(app.close, app.bridge)
|
||||||
session.setContent(app.createContentFunc(session))
|
session.setContent(app.createContentFunc(session))
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ func (app *wasmApp) init(params AppParams) {
|
||||||
body.Call("appendChild", div)
|
body.Call("appendChild", div)
|
||||||
|
|
||||||
if params.TitleColor != 0 {
|
if params.TitleColor != 0 {
|
||||||
app.brige.callFunc("setTitleColor", params.TitleColor.cssString())
|
app.bridge.callFunc("setTitleColor", params.TitleColor.cssString())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ func StartApp(addr string, createContentFunc func(Session) SessionContent, param
|
||||||
|
|
||||||
app := new(wasmApp)
|
app := new(wasmApp)
|
||||||
app.createContentFunc = createContentFunc
|
app.createContentFunc = createContentFunc
|
||||||
app.brige = createWasmBrige()
|
app.bridge = createWasmBridge()
|
||||||
|
|
||||||
app.init(params)
|
app.init(params)
|
||||||
<-app.close
|
<-app.close
|
||||||
|
|
|
@ -1799,13 +1799,15 @@ function appendStyles(styles) {
|
||||||
|
|
||||||
function getCanvasContext(elementId) {
|
function getCanvasContext(elementId) {
|
||||||
const canvas = document.getElementById(elementId)
|
const canvas = document.getElementById(elementId)
|
||||||
const ctx = canvas.getContext('2d');
|
if (canvas) {
|
||||||
const dpr = window.devicePixelRatio || 1;
|
const ctx = canvas.getContext('2d');
|
||||||
//var gradient;
|
if (ctx) {
|
||||||
//var path;
|
const dpr = window.devicePixelRatio || 1;
|
||||||
//var img;
|
ctx.canvas.width = dpr * canvas.clientWidth;
|
||||||
ctx.canvas.width = dpr * canvas.clientWidth;
|
ctx.canvas.height = dpr * canvas.clientHeight;
|
||||||
ctx.canvas.height = dpr * canvas.clientHeight;
|
ctx.scale(dpr, dpr);
|
||||||
ctx.scale(dpr, dpr);
|
return ctx;
|
||||||
return ctx;
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
13
canvas.go
13
canvas.go
|
@ -486,6 +486,19 @@ func (canvas *canvasData) SetLineCap(cap int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (canvas *canvasData) SetLineDash(dash []float64, offset float64) {
|
func (canvas *canvasData) SetLineDash(dash []float64, offset float64) {
|
||||||
|
/*buffer := allocStringBuilder()
|
||||||
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
|
lead := '['
|
||||||
|
for _, val := range dash {
|
||||||
|
buffer.WriteRune(lead)
|
||||||
|
lead = ','
|
||||||
|
buffer.WriteString(fmt.Sprintf("%g", val))
|
||||||
|
}
|
||||||
|
buffer.WriteRune(']')
|
||||||
|
|
||||||
|
canvas.session.callCanvasFunc("setLineDash", buffer.String())
|
||||||
|
*/
|
||||||
canvas.session.callCanvasFunc("setLineDash", dash)
|
canvas.session.callCanvasFunc("setLineDash", dash)
|
||||||
if offset >= 0 {
|
if offset >= 0 {
|
||||||
canvas.session.updateCanvasProperty("lineDashOffset", offset)
|
canvas.session.updateCanvasProperty("lineDashOffset", offset)
|
||||||
|
|
88
session.go
88
session.go
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type webBrige interface {
|
type webBridge interface {
|
||||||
startUpdateScript(htmlID string) bool
|
startUpdateScript(htmlID string) bool
|
||||||
finishUpdateScript(htmlID string)
|
finishUpdateScript(htmlID string)
|
||||||
callFunc(funcName string, args ...any) bool
|
callFunc(funcName string, args ...any) bool
|
||||||
|
@ -111,7 +111,7 @@ type Session interface {
|
||||||
nextViewID() string
|
nextViewID() string
|
||||||
styleProperty(styleTag, property string) any
|
styleProperty(styleTag, property string) any
|
||||||
|
|
||||||
setBrige(events chan DataObject, brige webBrige)
|
setBridge(events chan DataObject, bridge webBridge)
|
||||||
writeInitScript(writer *strings.Builder)
|
writeInitScript(writer *strings.Builder)
|
||||||
callFunc(funcName string, args ...any)
|
callFunc(funcName string, args ...any)
|
||||||
updateInnerHTML(htmlID, html string)
|
updateInnerHTML(htmlID, html string)
|
||||||
|
@ -175,7 +175,7 @@ type sessionData struct {
|
||||||
ignoreUpdates bool
|
ignoreUpdates bool
|
||||||
popups *popupManager
|
popups *popupManager
|
||||||
images *imageManager
|
images *imageManager
|
||||||
brige webBrige
|
bridge webBridge
|
||||||
events chan DataObject
|
events chan DataObject
|
||||||
animationCounter int
|
animationCounter int
|
||||||
animationCSS string
|
animationCSS string
|
||||||
|
@ -219,9 +219,9 @@ func (session *sessionData) ID() int {
|
||||||
return session.sessionID
|
return session.sessionID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) setBrige(events chan DataObject, brige webBrige) {
|
func (session *sessionData) setBridge(events chan DataObject, bridge webBridge) {
|
||||||
session.events = events
|
session.events = events
|
||||||
session.brige = brige
|
session.bridge = bridge
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) close() {
|
func (session *sessionData) close() {
|
||||||
|
@ -313,7 +313,7 @@ func (session *sessionData) reload() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) ignoreViewUpdates() bool {
|
func (session *sessionData) ignoreViewUpdates() bool {
|
||||||
return session.brige == nil || session.ignoreUpdates
|
return session.bridge == nil || session.ignoreUpdates
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) setIgnoreViewUpdates(ignore bool) {
|
func (session *sessionData) setIgnoreViewUpdates(ignore bool) {
|
||||||
|
@ -351,8 +351,8 @@ func (session *sessionData) imageManager() *imageManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) callFunc(funcName string, args ...any) {
|
func (session *sessionData) callFunc(funcName string, args ...any) {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
session.brige.callFunc(funcName, args...)
|
session.bridge.callFunc(funcName, args...)
|
||||||
} else {
|
} else {
|
||||||
ErrorLog("No connection")
|
ErrorLog("No connection")
|
||||||
}
|
}
|
||||||
|
@ -360,8 +360,8 @@ func (session *sessionData) callFunc(funcName string, args ...any) {
|
||||||
|
|
||||||
func (session *sessionData) updateInnerHTML(htmlID, html string) {
|
func (session *sessionData) updateInnerHTML(htmlID, html string) {
|
||||||
if !session.ignoreViewUpdates() {
|
if !session.ignoreViewUpdates() {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
session.brige.updateInnerHTML(htmlID, html)
|
session.bridge.updateInnerHTML(htmlID, html)
|
||||||
} else {
|
} else {
|
||||||
ErrorLog("No connection")
|
ErrorLog("No connection")
|
||||||
}
|
}
|
||||||
|
@ -370,8 +370,8 @@ func (session *sessionData) updateInnerHTML(htmlID, html string) {
|
||||||
|
|
||||||
func (session *sessionData) appendToInnerHTML(htmlID, html string) {
|
func (session *sessionData) appendToInnerHTML(htmlID, html string) {
|
||||||
if !session.ignoreViewUpdates() {
|
if !session.ignoreViewUpdates() {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
session.brige.appendToInnerHTML(htmlID, html)
|
session.bridge.appendToInnerHTML(htmlID, html)
|
||||||
} else {
|
} else {
|
||||||
ErrorLog("No connection")
|
ErrorLog("No connection")
|
||||||
}
|
}
|
||||||
|
@ -379,90 +379,90 @@ func (session *sessionData) appendToInnerHTML(htmlID, html string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) updateCSSProperty(htmlID, property, value string) {
|
func (session *sessionData) updateCSSProperty(htmlID, property, value string) {
|
||||||
if !session.ignoreViewUpdates() && session.brige != nil {
|
if !session.ignoreViewUpdates() && session.bridge != nil {
|
||||||
session.brige.updateCSSProperty(htmlID, property, value)
|
session.bridge.updateCSSProperty(htmlID, property, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) updateProperty(htmlID, property string, value any) {
|
func (session *sessionData) updateProperty(htmlID, property string, value any) {
|
||||||
if !session.ignoreViewUpdates() && session.brige != nil {
|
if !session.ignoreViewUpdates() && session.bridge != nil {
|
||||||
session.brige.updateProperty(htmlID, property, value)
|
session.bridge.updateProperty(htmlID, property, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) removeProperty(htmlID, property string) {
|
func (session *sessionData) removeProperty(htmlID, property string) {
|
||||||
if !session.ignoreViewUpdates() && session.brige != nil {
|
if !session.ignoreViewUpdates() && session.bridge != nil {
|
||||||
session.brige.removeProperty(htmlID, property)
|
session.bridge.removeProperty(htmlID, property)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) startUpdateScript(htmlID string) bool {
|
func (session *sessionData) startUpdateScript(htmlID string) bool {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
return session.brige.startUpdateScript(htmlID)
|
return session.bridge.startUpdateScript(htmlID)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) finishUpdateScript(htmlID string) {
|
func (session *sessionData) finishUpdateScript(htmlID string) {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
session.brige.finishUpdateScript(htmlID)
|
session.bridge.finishUpdateScript(htmlID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) cavnasStart(htmlID string) {
|
func (session *sessionData) cavnasStart(htmlID string) {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
session.brige.cavnasStart(htmlID)
|
session.bridge.cavnasStart(htmlID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) callCanvasFunc(funcName string, args ...any) {
|
func (session *sessionData) callCanvasFunc(funcName string, args ...any) {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
session.brige.callCanvasFunc(funcName, args...)
|
session.bridge.callCanvasFunc(funcName, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) updateCanvasProperty(property string, value any) {
|
func (session *sessionData) updateCanvasProperty(property string, value any) {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
session.brige.updateCanvasProperty(property, value)
|
session.bridge.updateCanvasProperty(property, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) createCanvasVar(funcName string, args ...any) any {
|
func (session *sessionData) createCanvasVar(funcName string, args ...any) any {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
return session.brige.createCanvasVar(funcName, args...)
|
return session.bridge.createCanvasVar(funcName, args...)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) callCanvasVarFunc(v any, funcName string, args ...any) {
|
func (session *sessionData) callCanvasVarFunc(v any, funcName string, args ...any) {
|
||||||
if session.brige != nil && v != nil {
|
if session.bridge != nil && v != nil {
|
||||||
session.brige.callCanvasVarFunc(v, funcName, args...)
|
session.bridge.callCanvasVarFunc(v, funcName, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) callCanvasImageFunc(url string, property string, funcName string, args ...any) {
|
func (session *sessionData) callCanvasImageFunc(url string, property string, funcName string, args ...any) {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
session.brige.callCanvasImageFunc(url, property, funcName, args...)
|
session.bridge.callCanvasImageFunc(url, property, funcName, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) cavnasFinish() {
|
func (session *sessionData) cavnasFinish() {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
session.brige.cavnasFinish()
|
session.bridge.cavnasFinish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) runScript(script string) {
|
func (session *sessionData) runScript(script string) {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
session.brige.writeMessage(script)
|
session.bridge.writeMessage(script)
|
||||||
} else {
|
} else {
|
||||||
ErrorLog("No connection")
|
ErrorLog("No connection")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) canvasTextMetrics(htmlID, font, text string) TextMetrics {
|
func (session *sessionData) canvasTextMetrics(htmlID, font, text string) TextMetrics {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
return session.brige.canvasTextMetrics(htmlID, font, text)
|
return session.bridge.canvasTextMetrics(htmlID, font, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLog("No connection")
|
ErrorLog("No connection")
|
||||||
|
@ -470,8 +470,8 @@ func (session *sessionData) canvasTextMetrics(htmlID, font, text string) TextMet
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) htmlPropertyValue(htmlID, name string) string {
|
func (session *sessionData) htmlPropertyValue(htmlID, name string) string {
|
||||||
if session.brige != nil {
|
if session.bridge != nil {
|
||||||
return session.brige.htmlPropertyValue(htmlID, name)
|
return session.bridge.htmlPropertyValue(htmlID, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLog("No connection")
|
ErrorLog("No connection")
|
||||||
|
@ -479,7 +479,7 @@ func (session *sessionData) htmlPropertyValue(htmlID, name string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) handleAnswer(data DataObject) {
|
func (session *sessionData) handleAnswer(data DataObject) {
|
||||||
session.brige.answerReceived(data)
|
session.bridge.answerReceived(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) handleRootSize(data DataObject) {
|
func (session *sessionData) handleRootSize(data DataObject) {
|
||||||
|
@ -620,7 +620,7 @@ func (session *sessionData) SetTitleColor(color Color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) RemoteAddr() string {
|
func (session *sessionData) RemoteAddr() string {
|
||||||
return session.brige.remoteAddr()
|
return session.bridge.remoteAddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) OpenURL(urlStr string) {
|
func (session *sessionData) OpenURL(urlStr string) {
|
||||||
|
|
|
@ -325,7 +325,7 @@ func (session *sessionData) SetLanguage(lang string) {
|
||||||
if lang != session.language {
|
if lang != session.language {
|
||||||
session.language = lang
|
session.language = lang
|
||||||
|
|
||||||
if session.rootView != nil && session.brige != nil {
|
if session.rootView != nil && session.bridge != nil {
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
|
@ -334,7 +334,7 @@ func (session *sessionData) SetLanguage(lang string) {
|
||||||
//buffer.WriteString("';\nscanElementsSize();")
|
//buffer.WriteString("';\nscanElementsSize();")
|
||||||
|
|
||||||
//session.runScript(buffer.String())
|
//session.runScript(buffer.String())
|
||||||
session.brige.updateInnerHTML("ruiRootView", buffer.String())
|
session.bridge.updateInnerHTML("ruiRootView", buffer.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
//go:build wasm
|
||||||
|
|
||||||
|
package rui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"syscall/js"
|
||||||
|
)
|
||||||
|
|
||||||
|
type wasmBridge struct {
|
||||||
|
queue chan string
|
||||||
|
answer map[int]chan DataObject
|
||||||
|
answerID int
|
||||||
|
answerMutex sync.Mutex
|
||||||
|
closed bool
|
||||||
|
canvas js.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func createWasmBridge() webBridge {
|
||||||
|
bridge := new(wasmBridge)
|
||||||
|
bridge.queue = make(chan string, 1000)
|
||||||
|
bridge.answerID = 1
|
||||||
|
bridge.answer = make(map[int]chan DataObject)
|
||||||
|
bridge.closed = false
|
||||||
|
|
||||||
|
return bridge
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) startUpdateScript(htmlID string) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) finishUpdateScript(htmlID string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) callFunc(funcName string, args ...any) bool {
|
||||||
|
if ProtocolInDebugLog {
|
||||||
|
text := funcName + "("
|
||||||
|
for i, arg := range args {
|
||||||
|
if i > 0 {
|
||||||
|
text += fmt.Sprintf(", `%v`", arg)
|
||||||
|
} else {
|
||||||
|
text += fmt.Sprintf("`%v`", arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DebugLog(text + ")")
|
||||||
|
}
|
||||||
|
|
||||||
|
js.Global().Call(funcName, args...)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) updateInnerHTML(htmlID, html string) {
|
||||||
|
bridge.callFunc("updateInnerHTML", htmlID, html)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) appendToInnerHTML(htmlID, html string) {
|
||||||
|
bridge.callFunc("appendToInnerHTML", htmlID, html)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) updateCSSProperty(htmlID, property, value string) {
|
||||||
|
bridge.callFunc("updateCSSProperty", htmlID, property, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) updateProperty(htmlID, property string, value any) {
|
||||||
|
bridge.callFunc("updateProperty", htmlID, property, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) removeProperty(htmlID, property string) {
|
||||||
|
bridge.callFunc("removeProperty", htmlID, property)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) readMessage() (string, bool) {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) writeMessage(script string) bool {
|
||||||
|
if ProtocolInDebugLog {
|
||||||
|
DebugLog("Run script:")
|
||||||
|
DebugLog(script)
|
||||||
|
}
|
||||||
|
|
||||||
|
window := js.Global().Get("window")
|
||||||
|
window.Call("execScript", script)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) cavnasStart(htmlID string) {
|
||||||
|
bridge.canvas = js.Global().Call("getCanvasContext", htmlID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) callCanvasFunc(funcName string, args ...any) {
|
||||||
|
if !bridge.canvas.IsNull() {
|
||||||
|
for i, arg := range args {
|
||||||
|
if array, ok := arg.([]float64); ok {
|
||||||
|
arr := make([]any, len(array))
|
||||||
|
for k, x := range array {
|
||||||
|
arr[k] = x
|
||||||
|
}
|
||||||
|
args[i] = js.ValueOf(array)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bridge.canvas.Call(funcName, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) callCanvasVarFunc(v any, funcName string, args ...any) {
|
||||||
|
if jsVar, ok := v.(js.Value); ok && !jsVar.IsNull() {
|
||||||
|
jsVar.Call(funcName, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) callCanvasImageFunc(url string, property string, funcName string, args ...any) {
|
||||||
|
image := js.Global().Get("images").Call("get", url)
|
||||||
|
if !image.IsUndefined() && !image.IsNull() {
|
||||||
|
result := image.Call(funcName, args...)
|
||||||
|
if property != "" {
|
||||||
|
bridge.canvas.Set(property, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) createCanvasVar(funcName string, args ...any) any {
|
||||||
|
if bridge.canvas.IsNull() {
|
||||||
|
return bridge.canvas
|
||||||
|
}
|
||||||
|
return bridge.canvas.Call(funcName, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) updateCanvasProperty(property string, value any) {
|
||||||
|
if !bridge.canvas.IsNull() {
|
||||||
|
bridge.canvas.Set(property, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) cavnasFinish() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) canvasTextMetrics(htmlID, font, text string) TextMetrics {
|
||||||
|
result := js.Global().Call("canvasTextMetrics", 0, htmlID, font, text).String()
|
||||||
|
DebugLog(result)
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
return TextMetrics{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) htmlPropertyValue(htmlID, name string) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) answerReceived(answer DataObject) {
|
||||||
|
if text, ok := answer.PropertyValue("answerID"); ok {
|
||||||
|
if id, err := strconv.Atoi(text); err == nil {
|
||||||
|
if chanel, ok := bridge.answer[id]; ok {
|
||||||
|
chanel <- answer
|
||||||
|
delete(bridge.answer, id)
|
||||||
|
} else {
|
||||||
|
ErrorLog("Bad answerID = " + text + " (chan not found)")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrorLog("Invalid answerID = " + text)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrorLog("answerID not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) remoteAddr() string {
|
||||||
|
return "localhost"
|
||||||
|
}
|
144
wasmBrige.go
144
wasmBrige.go
|
@ -1,144 +0,0 @@
|
||||||
//go:build wasm
|
|
||||||
|
|
||||||
package rui
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
"syscall/js"
|
|
||||||
)
|
|
||||||
|
|
||||||
type wasmBrige struct {
|
|
||||||
queue chan string
|
|
||||||
answer map[int]chan DataObject
|
|
||||||
answerID int
|
|
||||||
answerMutex sync.Mutex
|
|
||||||
closed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func createWasmBrige() webBrige {
|
|
||||||
brige := new(wasmBrige)
|
|
||||||
brige.queue = make(chan string, 1000)
|
|
||||||
brige.answerID = 1
|
|
||||||
brige.answer = make(map[int]chan DataObject)
|
|
||||||
brige.closed = false
|
|
||||||
|
|
||||||
return brige
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) startUpdateScript(htmlID string) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) finishUpdateScript(htmlID string) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) callFunc(funcName string, args ...any) bool {
|
|
||||||
if ProtocolInDebugLog {
|
|
||||||
text := funcName + "("
|
|
||||||
for i, arg := range args {
|
|
||||||
if i > 0 {
|
|
||||||
text += fmt.Sprintf(", `%v`", arg)
|
|
||||||
} else {
|
|
||||||
text += fmt.Sprintf("`%v`", arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DebugLog(text + ")")
|
|
||||||
}
|
|
||||||
|
|
||||||
js.Global().Call(funcName, args...)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) updateInnerHTML(htmlID, html string) {
|
|
||||||
brige.callFunc("updateInnerHTML", htmlID, html)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) appendToInnerHTML(htmlID, html string) {
|
|
||||||
brige.callFunc("appendToInnerHTML", htmlID, html)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) updateCSSProperty(htmlID, property, value string) {
|
|
||||||
brige.callFunc("updateCSSProperty", htmlID, property, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) updateProperty(htmlID, property string, value any) {
|
|
||||||
brige.callFunc("updateProperty", htmlID, property, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) removeProperty(htmlID, property string) {
|
|
||||||
brige.callFunc("removeProperty", htmlID, property)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) readMessage() (string, bool) {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) writeMessage(script string) bool {
|
|
||||||
if ProtocolInDebugLog {
|
|
||||||
DebugLog("Run script:")
|
|
||||||
DebugLog(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
window := js.Global().Get("window")
|
|
||||||
window.Call("execScript", script)
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
func (brige *wasmBrige) runGetterScript(script string) DataObject {
|
|
||||||
brige.answerMutex.Lock()
|
|
||||||
answerID := brige.answerID
|
|
||||||
brige.answerID++
|
|
||||||
brige.answerMutex.Unlock()
|
|
||||||
|
|
||||||
answer := make(chan DataObject)
|
|
||||||
brige.answer[answerID] = answer
|
|
||||||
errorText := ""
|
|
||||||
|
|
||||||
js.Global().Set("answerID", strconv.Itoa(answerID))
|
|
||||||
|
|
||||||
window := js.Global().Get("window")
|
|
||||||
window.Call("execScript", script)
|
|
||||||
|
|
||||||
result := NewDataObject("error")
|
|
||||||
result.SetPropertyValue("text", errorText)
|
|
||||||
delete(brige.answer, answerID)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (brige *wasmBrige) canvasTextMetrics(htmlID, font, text string) TextMetrics {
|
|
||||||
// TODO
|
|
||||||
return TextMetrics{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) htmlPropertyValue(htmlID, name string) string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) answerReceived(answer DataObject) {
|
|
||||||
if text, ok := answer.PropertyValue("answerID"); ok {
|
|
||||||
if id, err := strconv.Atoi(text); err == nil {
|
|
||||||
if chanel, ok := brige.answer[id]; ok {
|
|
||||||
chanel <- answer
|
|
||||||
delete(brige.answer, id)
|
|
||||||
} else {
|
|
||||||
ErrorLog("Bad answerID = " + text + " (chan not found)")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ErrorLog("Invalid answerID = " + text)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ErrorLog("answerID not found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wasmBrige) remoteAddr() string {
|
|
||||||
return "localhost"
|
|
||||||
}
|
|
|
@ -0,0 +1,418 @@
|
||||||
|
//go:build !wasm
|
||||||
|
|
||||||
|
package rui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
type wsBridge struct {
|
||||||
|
conn *websocket.Conn
|
||||||
|
answer map[int]chan DataObject
|
||||||
|
answerID int
|
||||||
|
answerMutex sync.Mutex
|
||||||
|
closed bool
|
||||||
|
buffer strings.Builder
|
||||||
|
canvasBuffer strings.Builder
|
||||||
|
canvasVarNumber int
|
||||||
|
updateScripts map[string]*strings.Builder
|
||||||
|
}
|
||||||
|
|
||||||
|
type canvasVar struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
var upgrader = websocket.Upgrader{
|
||||||
|
ReadBufferSize: 1024,
|
||||||
|
WriteBufferSize: 8096,
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateSocketBridge(w http.ResponseWriter, req *http.Request) webBridge {
|
||||||
|
conn, err := upgrader.Upgrade(w, req, nil)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
bridge := new(wsBridge)
|
||||||
|
bridge.answerID = 1
|
||||||
|
bridge.answer = make(map[int]chan DataObject)
|
||||||
|
bridge.conn = conn
|
||||||
|
bridge.closed = false
|
||||||
|
bridge.updateScripts = map[string]*strings.Builder{}
|
||||||
|
return bridge
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) close() {
|
||||||
|
bridge.closed = true
|
||||||
|
bridge.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) startUpdateScript(htmlID string) bool {
|
||||||
|
if _, ok := bridge.updateScripts[htmlID]; ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
buffer := allocStringBuilder()
|
||||||
|
bridge.updateScripts[htmlID] = buffer
|
||||||
|
buffer.WriteString("var element = document.getElementById('")
|
||||||
|
buffer.WriteString(htmlID)
|
||||||
|
buffer.WriteString("');\nif (element) {\n")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) finishUpdateScript(htmlID string) {
|
||||||
|
if buffer, ok := bridge.updateScripts[htmlID]; ok {
|
||||||
|
buffer.WriteString("scanElementsSize();\n}\n")
|
||||||
|
bridge.writeMessage(buffer.String())
|
||||||
|
freeStringBuilder(buffer)
|
||||||
|
delete(bridge.updateScripts, htmlID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) argToString(arg any) (string, bool) {
|
||||||
|
switch arg := arg.(type) {
|
||||||
|
case string:
|
||||||
|
arg = strings.ReplaceAll(arg, "\\", `\\`)
|
||||||
|
arg = strings.ReplaceAll(arg, "'", `\'`)
|
||||||
|
arg = strings.ReplaceAll(arg, "\n", `\n`)
|
||||||
|
arg = strings.ReplaceAll(arg, "\r", `\r`)
|
||||||
|
arg = strings.ReplaceAll(arg, "\t", `\t`)
|
||||||
|
arg = strings.ReplaceAll(arg, "\b", `\b`)
|
||||||
|
arg = strings.ReplaceAll(arg, "\f", `\f`)
|
||||||
|
arg = strings.ReplaceAll(arg, "\v", `\v`)
|
||||||
|
return `'` + arg + `'`, true
|
||||||
|
|
||||||
|
case rune:
|
||||||
|
switch arg {
|
||||||
|
case '\t':
|
||||||
|
return `'\t'`, true
|
||||||
|
case '\r':
|
||||||
|
return `'\r'`, true
|
||||||
|
case '\n':
|
||||||
|
return `'\n'`, true
|
||||||
|
case '\b':
|
||||||
|
return `'\b'`, true
|
||||||
|
case '\f':
|
||||||
|
return `'\f'`, true
|
||||||
|
case '\v':
|
||||||
|
return `'\v'`, true
|
||||||
|
case '\'':
|
||||||
|
return `'\''`, true
|
||||||
|
case '\\':
|
||||||
|
return `'\\'`, true
|
||||||
|
}
|
||||||
|
if arg < ' ' {
|
||||||
|
return fmt.Sprintf(`'\x%02d'`, int(arg)), true
|
||||||
|
}
|
||||||
|
return `'` + string(arg) + `'`, true
|
||||||
|
|
||||||
|
case bool:
|
||||||
|
if arg {
|
||||||
|
return "true", true
|
||||||
|
} else {
|
||||||
|
return "false", true
|
||||||
|
}
|
||||||
|
|
||||||
|
case float32:
|
||||||
|
return fmt.Sprintf("%g", float64(arg)), true
|
||||||
|
|
||||||
|
case float64:
|
||||||
|
return fmt.Sprintf("%g", arg), true
|
||||||
|
|
||||||
|
case []float64:
|
||||||
|
buffer := allocStringBuilder()
|
||||||
|
defer freeStringBuilder(buffer)
|
||||||
|
lead := '['
|
||||||
|
for _, val := range arg {
|
||||||
|
buffer.WriteRune(lead)
|
||||||
|
lead = ','
|
||||||
|
buffer.WriteString(fmt.Sprintf("%g", val))
|
||||||
|
}
|
||||||
|
buffer.WriteRune(']')
|
||||||
|
return buffer.String(), true
|
||||||
|
|
||||||
|
case canvasVar:
|
||||||
|
return arg.name, true
|
||||||
|
|
||||||
|
default:
|
||||||
|
if n, ok := isInt(arg); ok {
|
||||||
|
return fmt.Sprintf("%d", n), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorLog("Unsupported agument type")
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) callFunc(funcName string, args ...any) bool {
|
||||||
|
bridge.buffer.Reset()
|
||||||
|
bridge.buffer.WriteString(funcName)
|
||||||
|
bridge.buffer.WriteRune('(')
|
||||||
|
for i, arg := range args {
|
||||||
|
argText, ok := bridge.argToString(arg)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if i > 0 {
|
||||||
|
bridge.buffer.WriteString(", ")
|
||||||
|
}
|
||||||
|
bridge.buffer.WriteString(argText)
|
||||||
|
}
|
||||||
|
bridge.buffer.WriteString(");")
|
||||||
|
|
||||||
|
funcText := bridge.buffer.String()
|
||||||
|
if ProtocolInDebugLog {
|
||||||
|
DebugLog("Run func: " + funcText)
|
||||||
|
}
|
||||||
|
if err := bridge.conn.WriteMessage(websocket.TextMessage, []byte(funcText)); err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) updateInnerHTML(htmlID, html string) {
|
||||||
|
bridge.callFunc("updateInnerHTML", htmlID, html)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) appendToInnerHTML(htmlID, html string) {
|
||||||
|
bridge.callFunc("appendToInnerHTML", htmlID, html)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) updateCSSProperty(htmlID, property, value string) {
|
||||||
|
if buffer, ok := bridge.updateScripts[htmlID]; ok {
|
||||||
|
buffer.WriteString(`element.style['`)
|
||||||
|
buffer.WriteString(property)
|
||||||
|
buffer.WriteString(`'] = '`)
|
||||||
|
buffer.WriteString(value)
|
||||||
|
buffer.WriteString("';\n")
|
||||||
|
} else {
|
||||||
|
bridge.callFunc("updateCSSProperty", htmlID, property, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) updateProperty(htmlID, property string, value any) {
|
||||||
|
if buffer, ok := bridge.updateScripts[htmlID]; ok {
|
||||||
|
if val, ok := bridge.argToString(value); ok {
|
||||||
|
buffer.WriteString(`element.setAttribute('`)
|
||||||
|
buffer.WriteString(property)
|
||||||
|
buffer.WriteString(`', `)
|
||||||
|
buffer.WriteString(val)
|
||||||
|
buffer.WriteString(");\n")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bridge.callFunc("updateProperty", htmlID, property, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) removeProperty(htmlID, property string) {
|
||||||
|
if buffer, ok := bridge.updateScripts[htmlID]; ok {
|
||||||
|
buffer.WriteString(`if (element.hasAttribute('`)
|
||||||
|
buffer.WriteString(property)
|
||||||
|
buffer.WriteString(`')) { element.removeAttribute('`)
|
||||||
|
buffer.WriteString(property)
|
||||||
|
buffer.WriteString("');}\n")
|
||||||
|
} else {
|
||||||
|
bridge.callFunc("removeProperty", htmlID, property)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) cavnasStart(htmlID string) {
|
||||||
|
bridge.canvasBuffer.Reset()
|
||||||
|
bridge.canvasBuffer.WriteString(`const ctx = getCanvasContext('`)
|
||||||
|
bridge.canvasBuffer.WriteString(htmlID)
|
||||||
|
bridge.canvasBuffer.WriteString(`');`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) callCanvasFunc(funcName string, args ...any) {
|
||||||
|
bridge.canvasBuffer.WriteString("\nctx.")
|
||||||
|
bridge.canvasBuffer.WriteString(funcName)
|
||||||
|
bridge.canvasBuffer.WriteRune('(')
|
||||||
|
for i, arg := range args {
|
||||||
|
if i > 0 {
|
||||||
|
bridge.canvasBuffer.WriteString(", ")
|
||||||
|
}
|
||||||
|
argText, _ := bridge.argToString(arg)
|
||||||
|
bridge.canvasBuffer.WriteString(argText)
|
||||||
|
}
|
||||||
|
bridge.canvasBuffer.WriteString(");")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) updateCanvasProperty(property string, value any) {
|
||||||
|
bridge.canvasBuffer.WriteString("\nctx.")
|
||||||
|
bridge.canvasBuffer.WriteString(property)
|
||||||
|
bridge.canvasBuffer.WriteString(" = ")
|
||||||
|
argText, _ := bridge.argToString(value)
|
||||||
|
bridge.canvasBuffer.WriteString(argText)
|
||||||
|
bridge.canvasBuffer.WriteString(";")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) createCanvasVar(funcName string, args ...any) any {
|
||||||
|
bridge.canvasVarNumber++
|
||||||
|
result := canvasVar{name: fmt.Sprintf("v%d", bridge.canvasVarNumber)}
|
||||||
|
bridge.canvasBuffer.WriteString("\nvar ")
|
||||||
|
bridge.canvasBuffer.WriteString(result.name)
|
||||||
|
bridge.canvasBuffer.WriteString(" = ctx.")
|
||||||
|
bridge.canvasBuffer.WriteString(funcName)
|
||||||
|
bridge.canvasBuffer.WriteRune('(')
|
||||||
|
for i, arg := range args {
|
||||||
|
if i > 0 {
|
||||||
|
bridge.canvasBuffer.WriteString(", ")
|
||||||
|
}
|
||||||
|
argText, _ := bridge.argToString(arg)
|
||||||
|
bridge.canvasBuffer.WriteString(argText)
|
||||||
|
}
|
||||||
|
bridge.canvasBuffer.WriteString(");")
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) callCanvasVarFunc(v any, funcName string, args ...any) {
|
||||||
|
varName, ok := v.(canvasVar)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bridge.canvasBuffer.WriteString("\n")
|
||||||
|
bridge.canvasBuffer.WriteString(varName.name)
|
||||||
|
bridge.canvasBuffer.WriteRune('.')
|
||||||
|
bridge.canvasBuffer.WriteString(funcName)
|
||||||
|
bridge.canvasBuffer.WriteRune('(')
|
||||||
|
for i, arg := range args {
|
||||||
|
if i > 0 {
|
||||||
|
bridge.canvasBuffer.WriteString(", ")
|
||||||
|
}
|
||||||
|
argText, _ := bridge.argToString(arg)
|
||||||
|
bridge.canvasBuffer.WriteString(argText)
|
||||||
|
}
|
||||||
|
bridge.canvasBuffer.WriteString(");")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) callCanvasImageFunc(url string, property string, funcName string, args ...any) {
|
||||||
|
|
||||||
|
bridge.canvasBuffer.WriteString("\nimg = images.get('")
|
||||||
|
bridge.canvasBuffer.WriteString(url)
|
||||||
|
bridge.canvasBuffer.WriteString("');\nif (img) {\n")
|
||||||
|
if property != "" {
|
||||||
|
bridge.canvasBuffer.WriteString("ctx.")
|
||||||
|
bridge.canvasBuffer.WriteString(property)
|
||||||
|
bridge.canvasBuffer.WriteString(" = ")
|
||||||
|
}
|
||||||
|
bridge.canvasBuffer.WriteString("ctx.")
|
||||||
|
bridge.canvasBuffer.WriteString(funcName)
|
||||||
|
bridge.canvasBuffer.WriteString("(img")
|
||||||
|
for _, arg := range args {
|
||||||
|
bridge.canvasBuffer.WriteString(", ")
|
||||||
|
argText, _ := bridge.argToString(arg)
|
||||||
|
bridge.canvasBuffer.WriteString(argText)
|
||||||
|
}
|
||||||
|
bridge.canvasBuffer.WriteString(");\n}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) cavnasFinish() {
|
||||||
|
bridge.canvasBuffer.WriteString("\n")
|
||||||
|
script := bridge.canvasBuffer.String()
|
||||||
|
if ProtocolInDebugLog {
|
||||||
|
DebugLog("Run script:")
|
||||||
|
DebugLog(script)
|
||||||
|
}
|
||||||
|
if bridge.conn == nil {
|
||||||
|
ErrorLog("No connection")
|
||||||
|
} else if err := bridge.conn.WriteMessage(websocket.TextMessage, []byte(script)); err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) readMessage() (string, bool) {
|
||||||
|
_, p, err := bridge.conn.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
if !bridge.closed {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(p), true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) writeMessage(script string) bool {
|
||||||
|
if ProtocolInDebugLog {
|
||||||
|
DebugLog("Run script:")
|
||||||
|
DebugLog(script)
|
||||||
|
}
|
||||||
|
if bridge.conn == nil {
|
||||||
|
ErrorLog("No connection")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if err := bridge.conn.WriteMessage(websocket.TextMessage, []byte(script)); err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) canvasTextMetrics(htmlID, font, text string) TextMetrics {
|
||||||
|
result := TextMetrics{}
|
||||||
|
|
||||||
|
bridge.answerMutex.Lock()
|
||||||
|
answerID := bridge.answerID
|
||||||
|
bridge.answerID++
|
||||||
|
bridge.answerMutex.Unlock()
|
||||||
|
|
||||||
|
answer := make(chan DataObject)
|
||||||
|
bridge.answer[answerID] = answer
|
||||||
|
|
||||||
|
if bridge.callFunc("canvasTextMetrics", answerID, htmlID, font, text) {
|
||||||
|
data := <-answer
|
||||||
|
result.Width = dataFloatProperty(data, "width")
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(bridge.answer, answerID)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) htmlPropertyValue(htmlID, name string) string {
|
||||||
|
bridge.answerMutex.Lock()
|
||||||
|
answerID := bridge.answerID
|
||||||
|
bridge.answerID++
|
||||||
|
bridge.answerMutex.Unlock()
|
||||||
|
|
||||||
|
answer := make(chan DataObject)
|
||||||
|
bridge.answer[answerID] = answer
|
||||||
|
|
||||||
|
if bridge.callFunc("getPropertyValue", answerID, htmlID, name) {
|
||||||
|
data := <-answer
|
||||||
|
if value, ok := data.PropertyValue("value"); ok {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(bridge.answer, answerID)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) answerReceived(answer DataObject) {
|
||||||
|
if text, ok := answer.PropertyValue("answerID"); ok {
|
||||||
|
if id, err := strconv.Atoi(text); err == nil {
|
||||||
|
if chanel, ok := bridge.answer[id]; ok {
|
||||||
|
chanel <- answer
|
||||||
|
delete(bridge.answer, id)
|
||||||
|
} else {
|
||||||
|
ErrorLog("Bad answerID = " + text + " (chan not found)")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrorLog("Invalid answerID = " + text)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrorLog("answerID not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) remoteAddr() string {
|
||||||
|
return bridge.conn.RemoteAddr().String()
|
||||||
|
}
|
418
webBrige.go
418
webBrige.go
|
@ -1,418 +0,0 @@
|
||||||
//go:build !wasm
|
|
||||||
|
|
||||||
package rui
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
)
|
|
||||||
|
|
||||||
type wsBrige struct {
|
|
||||||
conn *websocket.Conn
|
|
||||||
answer map[int]chan DataObject
|
|
||||||
answerID int
|
|
||||||
answerMutex sync.Mutex
|
|
||||||
closed bool
|
|
||||||
buffer strings.Builder
|
|
||||||
canvasBuffer strings.Builder
|
|
||||||
canvasVarNumber int
|
|
||||||
updateScripts map[string]*strings.Builder
|
|
||||||
}
|
|
||||||
|
|
||||||
type canvasVar struct {
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
|
|
||||||
var upgrader = websocket.Upgrader{
|
|
||||||
ReadBufferSize: 1024,
|
|
||||||
WriteBufferSize: 8096,
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateSocketBrige(w http.ResponseWriter, req *http.Request) webBrige {
|
|
||||||
conn, err := upgrader.Upgrade(w, req, nil)
|
|
||||||
if err != nil {
|
|
||||||
ErrorLog(err.Error())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
brige := new(wsBrige)
|
|
||||||
brige.answerID = 1
|
|
||||||
brige.answer = make(map[int]chan DataObject)
|
|
||||||
brige.conn = conn
|
|
||||||
brige.closed = false
|
|
||||||
brige.updateScripts = map[string]*strings.Builder{}
|
|
||||||
return brige
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) close() {
|
|
||||||
brige.closed = true
|
|
||||||
brige.conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) startUpdateScript(htmlID string) bool {
|
|
||||||
if _, ok := brige.updateScripts[htmlID]; ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
buffer := allocStringBuilder()
|
|
||||||
brige.updateScripts[htmlID] = buffer
|
|
||||||
buffer.WriteString("var element = document.getElementById('")
|
|
||||||
buffer.WriteString(htmlID)
|
|
||||||
buffer.WriteString("');\nif (element) {\n")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) finishUpdateScript(htmlID string) {
|
|
||||||
if buffer, ok := brige.updateScripts[htmlID]; ok {
|
|
||||||
buffer.WriteString("scanElementsSize();\n}\n")
|
|
||||||
brige.writeMessage(buffer.String())
|
|
||||||
freeStringBuilder(buffer)
|
|
||||||
delete(brige.updateScripts, htmlID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) argToString(arg any) (string, bool) {
|
|
||||||
switch arg := arg.(type) {
|
|
||||||
case string:
|
|
||||||
arg = strings.ReplaceAll(arg, "\\", `\\`)
|
|
||||||
arg = strings.ReplaceAll(arg, "'", `\'`)
|
|
||||||
arg = strings.ReplaceAll(arg, "\n", `\n`)
|
|
||||||
arg = strings.ReplaceAll(arg, "\r", `\r`)
|
|
||||||
arg = strings.ReplaceAll(arg, "\t", `\t`)
|
|
||||||
arg = strings.ReplaceAll(arg, "\b", `\b`)
|
|
||||||
arg = strings.ReplaceAll(arg, "\f", `\f`)
|
|
||||||
arg = strings.ReplaceAll(arg, "\v", `\v`)
|
|
||||||
return `'` + arg + `'`, true
|
|
||||||
|
|
||||||
case rune:
|
|
||||||
switch arg {
|
|
||||||
case '\t':
|
|
||||||
return `'\t'`, true
|
|
||||||
case '\r':
|
|
||||||
return `'\r'`, true
|
|
||||||
case '\n':
|
|
||||||
return `'\n'`, true
|
|
||||||
case '\b':
|
|
||||||
return `'\b'`, true
|
|
||||||
case '\f':
|
|
||||||
return `'\f'`, true
|
|
||||||
case '\v':
|
|
||||||
return `'\v'`, true
|
|
||||||
case '\'':
|
|
||||||
return `'\''`, true
|
|
||||||
case '\\':
|
|
||||||
return `'\\'`, true
|
|
||||||
}
|
|
||||||
if arg < ' ' {
|
|
||||||
return fmt.Sprintf(`'\x%02d'`, int(arg)), true
|
|
||||||
}
|
|
||||||
return `'` + string(arg) + `'`, true
|
|
||||||
|
|
||||||
case bool:
|
|
||||||
if arg {
|
|
||||||
return "true", true
|
|
||||||
} else {
|
|
||||||
return "false", true
|
|
||||||
}
|
|
||||||
|
|
||||||
case float32:
|
|
||||||
return fmt.Sprintf("%g", float64(arg)), true
|
|
||||||
|
|
||||||
case float64:
|
|
||||||
return fmt.Sprintf("%g", arg), true
|
|
||||||
|
|
||||||
case []float64:
|
|
||||||
buffer := allocStringBuilder()
|
|
||||||
defer freeStringBuilder(buffer)
|
|
||||||
lead := '['
|
|
||||||
for _, val := range arg {
|
|
||||||
buffer.WriteRune(lead)
|
|
||||||
lead = ','
|
|
||||||
buffer.WriteString(fmt.Sprintf("%g", val))
|
|
||||||
}
|
|
||||||
buffer.WriteRune(']')
|
|
||||||
return buffer.String(), true
|
|
||||||
|
|
||||||
case canvasVar:
|
|
||||||
return arg.name, true
|
|
||||||
|
|
||||||
default:
|
|
||||||
if n, ok := isInt(arg); ok {
|
|
||||||
return fmt.Sprintf("%d", n), true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorLog("Unsupported agument type")
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) callFunc(funcName string, args ...any) bool {
|
|
||||||
brige.buffer.Reset()
|
|
||||||
brige.buffer.WriteString(funcName)
|
|
||||||
brige.buffer.WriteRune('(')
|
|
||||||
for i, arg := range args {
|
|
||||||
argText, ok := brige.argToString(arg)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if i > 0 {
|
|
||||||
brige.buffer.WriteString(", ")
|
|
||||||
}
|
|
||||||
brige.buffer.WriteString(argText)
|
|
||||||
}
|
|
||||||
brige.buffer.WriteString(");")
|
|
||||||
|
|
||||||
funcText := brige.buffer.String()
|
|
||||||
if ProtocolInDebugLog {
|
|
||||||
DebugLog("Run func: " + funcText)
|
|
||||||
}
|
|
||||||
if err := brige.conn.WriteMessage(websocket.TextMessage, []byte(funcText)); err != nil {
|
|
||||||
ErrorLog(err.Error())
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) updateInnerHTML(htmlID, html string) {
|
|
||||||
brige.callFunc("updateInnerHTML", htmlID, html)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) appendToInnerHTML(htmlID, html string) {
|
|
||||||
brige.callFunc("appendToInnerHTML", htmlID, html)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) updateCSSProperty(htmlID, property, value string) {
|
|
||||||
if buffer, ok := brige.updateScripts[htmlID]; ok {
|
|
||||||
buffer.WriteString(`element.style['`)
|
|
||||||
buffer.WriteString(property)
|
|
||||||
buffer.WriteString(`'] = '`)
|
|
||||||
buffer.WriteString(value)
|
|
||||||
buffer.WriteString("';\n")
|
|
||||||
} else {
|
|
||||||
brige.callFunc("updateCSSProperty", htmlID, property, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) updateProperty(htmlID, property string, value any) {
|
|
||||||
if buffer, ok := brige.updateScripts[htmlID]; ok {
|
|
||||||
if val, ok := brige.argToString(value); ok {
|
|
||||||
buffer.WriteString(`element.setAttribute('`)
|
|
||||||
buffer.WriteString(property)
|
|
||||||
buffer.WriteString(`', `)
|
|
||||||
buffer.WriteString(val)
|
|
||||||
buffer.WriteString(");\n")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
brige.callFunc("updateProperty", htmlID, property, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) removeProperty(htmlID, property string) {
|
|
||||||
if buffer, ok := brige.updateScripts[htmlID]; ok {
|
|
||||||
buffer.WriteString(`if (element.hasAttribute('`)
|
|
||||||
buffer.WriteString(property)
|
|
||||||
buffer.WriteString(`')) { element.removeAttribute('`)
|
|
||||||
buffer.WriteString(property)
|
|
||||||
buffer.WriteString("');}\n")
|
|
||||||
} else {
|
|
||||||
brige.callFunc("removeProperty", htmlID, property)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) cavnasStart(htmlID string) {
|
|
||||||
brige.canvasBuffer.Reset()
|
|
||||||
brige.canvasBuffer.WriteString(`const ctx = getCanvasContext('`)
|
|
||||||
brige.canvasBuffer.WriteString(htmlID)
|
|
||||||
brige.canvasBuffer.WriteString(`');`)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) callCanvasFunc(funcName string, args ...any) {
|
|
||||||
brige.canvasBuffer.WriteString("\nctx.")
|
|
||||||
brige.canvasBuffer.WriteString(funcName)
|
|
||||||
brige.canvasBuffer.WriteRune('(')
|
|
||||||
for i, arg := range args {
|
|
||||||
if i > 0 {
|
|
||||||
brige.canvasBuffer.WriteString(", ")
|
|
||||||
}
|
|
||||||
argText, _ := brige.argToString(arg)
|
|
||||||
brige.canvasBuffer.WriteString(argText)
|
|
||||||
}
|
|
||||||
brige.canvasBuffer.WriteString(");")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) updateCanvasProperty(property string, value any) {
|
|
||||||
brige.canvasBuffer.WriteString("\nctx.")
|
|
||||||
brige.canvasBuffer.WriteString(property)
|
|
||||||
brige.canvasBuffer.WriteString(" = ")
|
|
||||||
argText, _ := brige.argToString(value)
|
|
||||||
brige.canvasBuffer.WriteString(argText)
|
|
||||||
brige.canvasBuffer.WriteString(";")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) createCanvasVar(funcName string, args ...any) any {
|
|
||||||
brige.canvasVarNumber++
|
|
||||||
result := canvasVar{name: fmt.Sprintf("v%d", brige.canvasVarNumber)}
|
|
||||||
brige.canvasBuffer.WriteString("\nvar ")
|
|
||||||
brige.canvasBuffer.WriteString(result.name)
|
|
||||||
brige.canvasBuffer.WriteString(" = ctx.")
|
|
||||||
brige.canvasBuffer.WriteString(funcName)
|
|
||||||
brige.canvasBuffer.WriteRune('(')
|
|
||||||
for i, arg := range args {
|
|
||||||
if i > 0 {
|
|
||||||
brige.canvasBuffer.WriteString(", ")
|
|
||||||
}
|
|
||||||
argText, _ := brige.argToString(arg)
|
|
||||||
brige.canvasBuffer.WriteString(argText)
|
|
||||||
}
|
|
||||||
brige.canvasBuffer.WriteString(");")
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) callCanvasVarFunc(v any, funcName string, args ...any) {
|
|
||||||
varName, ok := v.(canvasVar)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
brige.canvasBuffer.WriteString("\n")
|
|
||||||
brige.canvasBuffer.WriteString(varName.name)
|
|
||||||
brige.canvasBuffer.WriteRune('.')
|
|
||||||
brige.canvasBuffer.WriteString(funcName)
|
|
||||||
brige.canvasBuffer.WriteRune('(')
|
|
||||||
for i, arg := range args {
|
|
||||||
if i > 0 {
|
|
||||||
brige.canvasBuffer.WriteString(", ")
|
|
||||||
}
|
|
||||||
argText, _ := brige.argToString(arg)
|
|
||||||
brige.canvasBuffer.WriteString(argText)
|
|
||||||
}
|
|
||||||
brige.canvasBuffer.WriteString(");")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) callCanvasImageFunc(url string, property string, funcName string, args ...any) {
|
|
||||||
|
|
||||||
brige.canvasBuffer.WriteString("\nimg = images.get('")
|
|
||||||
brige.canvasBuffer.WriteString(url)
|
|
||||||
brige.canvasBuffer.WriteString("');\nif (img) {\n")
|
|
||||||
if property != "" {
|
|
||||||
brige.canvasBuffer.WriteString("ctx.")
|
|
||||||
brige.canvasBuffer.WriteString(property)
|
|
||||||
brige.canvasBuffer.WriteString(" = ")
|
|
||||||
}
|
|
||||||
brige.canvasBuffer.WriteString("ctx.")
|
|
||||||
brige.canvasBuffer.WriteString(funcName)
|
|
||||||
brige.canvasBuffer.WriteString("(img")
|
|
||||||
for _, arg := range args {
|
|
||||||
brige.canvasBuffer.WriteString(", ")
|
|
||||||
argText, _ := brige.argToString(arg)
|
|
||||||
brige.canvasBuffer.WriteString(argText)
|
|
||||||
}
|
|
||||||
brige.canvasBuffer.WriteString(");\n}")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) cavnasFinish() {
|
|
||||||
brige.canvasBuffer.WriteString("\n")
|
|
||||||
script := brige.canvasBuffer.String()
|
|
||||||
if ProtocolInDebugLog {
|
|
||||||
DebugLog("Run script:")
|
|
||||||
DebugLog(script)
|
|
||||||
}
|
|
||||||
if brige.conn == nil {
|
|
||||||
ErrorLog("No connection")
|
|
||||||
} else if err := brige.conn.WriteMessage(websocket.TextMessage, []byte(script)); err != nil {
|
|
||||||
ErrorLog(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) readMessage() (string, bool) {
|
|
||||||
_, p, err := brige.conn.ReadMessage()
|
|
||||||
if err != nil {
|
|
||||||
if !brige.closed {
|
|
||||||
ErrorLog(err.Error())
|
|
||||||
}
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(p), true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) writeMessage(script string) bool {
|
|
||||||
if ProtocolInDebugLog {
|
|
||||||
DebugLog("Run script:")
|
|
||||||
DebugLog(script)
|
|
||||||
}
|
|
||||||
if brige.conn == nil {
|
|
||||||
ErrorLog("No connection")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if err := brige.conn.WriteMessage(websocket.TextMessage, []byte(script)); err != nil {
|
|
||||||
ErrorLog(err.Error())
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) canvasTextMetrics(htmlID, font, text string) TextMetrics {
|
|
||||||
result := TextMetrics{}
|
|
||||||
|
|
||||||
brige.answerMutex.Lock()
|
|
||||||
answerID := brige.answerID
|
|
||||||
brige.answerID++
|
|
||||||
brige.answerMutex.Unlock()
|
|
||||||
|
|
||||||
answer := make(chan DataObject)
|
|
||||||
brige.answer[answerID] = answer
|
|
||||||
|
|
||||||
if brige.callFunc("canvasTextMetrics", answerID, htmlID, font, text) {
|
|
||||||
data := <-answer
|
|
||||||
result.Width = dataFloatProperty(data, "width")
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(brige.answer, answerID)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) htmlPropertyValue(htmlID, name string) string {
|
|
||||||
brige.answerMutex.Lock()
|
|
||||||
answerID := brige.answerID
|
|
||||||
brige.answerID++
|
|
||||||
brige.answerMutex.Unlock()
|
|
||||||
|
|
||||||
answer := make(chan DataObject)
|
|
||||||
brige.answer[answerID] = answer
|
|
||||||
|
|
||||||
if brige.callFunc("getPropertyValue", answerID, htmlID, name) {
|
|
||||||
data := <-answer
|
|
||||||
if value, ok := data.PropertyValue("value"); ok {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(brige.answer, answerID)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) answerReceived(answer DataObject) {
|
|
||||||
if text, ok := answer.PropertyValue("answerID"); ok {
|
|
||||||
if id, err := strconv.Atoi(text); err == nil {
|
|
||||||
if chanel, ok := brige.answer[id]; ok {
|
|
||||||
chanel <- answer
|
|
||||||
delete(brige.answer, id)
|
|
||||||
} else {
|
|
||||||
ErrorLog("Bad answerID = " + text + " (chan not found)")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ErrorLog("Invalid answerID = " + text)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ErrorLog("answerID not found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (brige *wsBrige) remoteAddr() string {
|
|
||||||
return brige.conn.RemoteAddr().String()
|
|
||||||
}
|
|
Loading…
Reference in New Issue