forked from mbk-lab/rui_orig
Added NoSocket parameter of the app
This commit is contained in:
parent
30c915d73b
commit
ebcba7f9c2
164
appServer.go
164
appServer.go
|
@ -20,6 +20,9 @@ import (
|
||||||
//go:embed app_socket.js
|
//go:embed app_socket.js
|
||||||
var socketScripts string
|
var socketScripts string
|
||||||
|
|
||||||
|
//go:embed app_post.js
|
||||||
|
var httpPostScripts string
|
||||||
|
|
||||||
func debugLog(text string) {
|
func debugLog(text string) {
|
||||||
log.Println("\033[34m" + text)
|
log.Println("\033[34m" + text)
|
||||||
}
|
}
|
||||||
|
@ -28,11 +31,16 @@ func errorLog(text string) {
|
||||||
log.Println("\033[31m" + text)
|
log.Println("\033[31m" + text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type sessionInfo struct {
|
||||||
|
session Session
|
||||||
|
response chan string
|
||||||
|
}
|
||||||
|
|
||||||
type application struct {
|
type application struct {
|
||||||
server *http.Server
|
server *http.Server
|
||||||
params AppParams
|
params AppParams
|
||||||
createContentFunc func(Session) SessionContent
|
createContentFunc func(Session) SessionContent
|
||||||
sessions map[int]Session
|
sessions map[int]sessionInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) getStartPage() string {
|
func (app *application) getStartPage() string {
|
||||||
|
@ -40,14 +48,18 @@ func (app *application) getStartPage() string {
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
buffer.WriteString("<!DOCTYPE html>\n<html>\n")
|
buffer.WriteString("<!DOCTYPE html>\n<html>\n")
|
||||||
getStartPage(buffer, app.params, socketScripts)
|
getStartPage(buffer, app.params)
|
||||||
buffer.WriteString("\n</html>")
|
buffer.WriteString("\n</html>")
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) Finish() {
|
func (app *application) Finish() {
|
||||||
for _, session := range app.sessions {
|
for _, session := range app.sessions {
|
||||||
session.close()
|
session.session.close()
|
||||||
|
if session.response != nil {
|
||||||
|
close(session.response)
|
||||||
|
session.response = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
@ -69,7 +81,12 @@ func (app *application) nextSessionID() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) removeSession(id int) {
|
func (app *application) removeSession(id int) {
|
||||||
delete(app.sessions, id)
|
if info, ok := app.sessions[id]; ok {
|
||||||
|
if info.response != nil {
|
||||||
|
close(info.response)
|
||||||
|
}
|
||||||
|
delete(app.sessions, id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
func (app *application) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
@ -79,6 +96,11 @@ func (app *application) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch req.Method {
|
switch req.Method {
|
||||||
|
case "POST":
|
||||||
|
if req.URL.Path == "/" {
|
||||||
|
app.postHandler(w, req)
|
||||||
|
}
|
||||||
|
|
||||||
case "GET":
|
case "GET":
|
||||||
switch req.URL.Path {
|
switch req.URL.Path {
|
||||||
case "/":
|
case "/":
|
||||||
|
@ -86,10 +108,20 @@ 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 bridge := CreateSocketBridge(w, req); bridge != nil {
|
if bridge := createSocketBridge(w, req); bridge != nil {
|
||||||
go app.socketReader(bridge)
|
go app.socketReader(bridge)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "/script.js":
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
if app.params.NoSocket {
|
||||||
|
io.WriteString(w, httpPostScripts)
|
||||||
|
} else {
|
||||||
|
io.WriteString(w, socketScripts)
|
||||||
|
}
|
||||||
|
io.WriteString(w, "\n")
|
||||||
|
io.WriteString(w, defaultScripts)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
filename := req.URL.Path[1:]
|
filename := req.URL.Path[1:]
|
||||||
if size := len(filename); size > 0 && filename[size-1] == '/' {
|
if size := len(filename); size > 0 && filename[size-1] == '/' {
|
||||||
|
@ -104,7 +136,92 @@ func (app *application) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) socketReader(bridge webBridge) {
|
func setSessionIDCookie(w http.ResponseWriter, sessionID int) {
|
||||||
|
cookie := http.Cookie{
|
||||||
|
Name: "session",
|
||||||
|
Value: strconv.Itoa(sessionID),
|
||||||
|
HttpOnly: true,
|
||||||
|
}
|
||||||
|
http.SetCookie(w, &cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *application) postHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
|
if reqBody, err := io.ReadAll(req.Body); err == nil {
|
||||||
|
message := string(reqBody)
|
||||||
|
|
||||||
|
if ProtocolInDebugLog {
|
||||||
|
DebugLog(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj := ParseDataText(message); obj != nil {
|
||||||
|
var session Session = nil
|
||||||
|
var response chan string = nil
|
||||||
|
|
||||||
|
if cookie, err := req.Cookie("session"); err == nil {
|
||||||
|
sessionID, err := strconv.Atoi(cookie.Value)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else if info, ok := app.sessions[sessionID]; ok && info.response != nil {
|
||||||
|
response = info.response
|
||||||
|
session = info.session
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command := obj.Tag()
|
||||||
|
|
||||||
|
if session == nil {
|
||||||
|
switch command {
|
||||||
|
case "startSession":
|
||||||
|
events := make(chan DataObject, 1024)
|
||||||
|
bridge := createHttpBridge(req)
|
||||||
|
response = bridge.response
|
||||||
|
answer := ""
|
||||||
|
session, answer = app.startSession(obj, events, bridge, response)
|
||||||
|
|
||||||
|
bridge.writeMessage(answer)
|
||||||
|
session.onStart()
|
||||||
|
bridge.sendResponse()
|
||||||
|
|
||||||
|
setSessionIDCookie(w, session.ID())
|
||||||
|
|
||||||
|
go sessionEventHandler(session, events, bridge)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch command {
|
||||||
|
case "startSession":
|
||||||
|
|
||||||
|
case "nop":
|
||||||
|
session.sendResponse()
|
||||||
|
/*
|
||||||
|
case "disconnect":
|
||||||
|
session.onDisconnect()
|
||||||
|
return
|
||||||
|
*/
|
||||||
|
case "session-close":
|
||||||
|
session.onFinish()
|
||||||
|
session.App().removeSession(session.ID())
|
||||||
|
return
|
||||||
|
|
||||||
|
default:
|
||||||
|
if !session.handleAnswer(command, obj) {
|
||||||
|
session.addToEventsQueue(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
io.WriteString(w, <-response)
|
||||||
|
for len(response) > 0 {
|
||||||
|
io.WriteString(w, <-response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *application) socketReader(bridge *wsBridge) {
|
||||||
var session Session
|
var session Session
|
||||||
events := make(chan DataObject, 1024)
|
events := make(chan DataObject, 1024)
|
||||||
|
|
||||||
|
@ -116,7 +233,7 @@ func (app *application) socketReader(bridge webBridge) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ProtocolInDebugLog {
|
if ProtocolInDebugLog {
|
||||||
DebugLog(message)
|
DebugLog("🖥️ -> " + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj := ParseDataText(message); obj != nil {
|
if obj := ParseDataText(message); obj != nil {
|
||||||
|
@ -124,7 +241,7 @@ func (app *application) socketReader(bridge webBridge) {
|
||||||
switch command {
|
switch command {
|
||||||
case "startSession":
|
case "startSession":
|
||||||
answer := ""
|
answer := ""
|
||||||
if session, answer = app.startSession(obj, events, bridge); session != nil {
|
if session, answer = app.startSession(obj, events, bridge, nil); session != nil {
|
||||||
if !bridge.writeMessage(answer) {
|
if !bridge.writeMessage(answer) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -135,7 +252,8 @@ func (app *application) socketReader(bridge webBridge) {
|
||||||
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 info, ok := app.sessions[sessionID]; ok {
|
||||||
|
session := info.session
|
||||||
session.setBridge(events, bridge)
|
session.setBridge(events, bridge)
|
||||||
answer := allocStringBuilder()
|
answer := allocStringBuilder()
|
||||||
defer freeStringBuilder(answer)
|
defer freeStringBuilder(answer)
|
||||||
|
@ -157,7 +275,7 @@ func (app *application) socketReader(bridge webBridge) {
|
||||||
}
|
}
|
||||||
|
|
||||||
answer := ""
|
answer := ""
|
||||||
if session, answer = app.startSession(obj, events, bridge); session != nil {
|
if session, answer = app.startSession(obj, events, bridge, nil); session != nil {
|
||||||
if !bridge.writeMessage(answer) {
|
if !bridge.writeMessage(answer) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -165,23 +283,16 @@ func (app *application) socketReader(bridge webBridge) {
|
||||||
go sessionEventHandler(session, events, bridge)
|
go sessionEventHandler(session, events, bridge)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "answer":
|
|
||||||
session.handleAnswer(obj)
|
|
||||||
|
|
||||||
case "imageLoaded":
|
|
||||||
session.imageManager().imageLoaded(obj)
|
|
||||||
|
|
||||||
case "imageError":
|
|
||||||
session.imageManager().imageLoadError(obj)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
events <- obj
|
if !session.handleAnswer(command, obj) {
|
||||||
|
events <- obj
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sessionEventHandler(session Session, events chan DataObject, bridge webBridge) {
|
func sessionEventHandler(session Session, events chan DataObject, bridge bridge) {
|
||||||
for {
|
for {
|
||||||
data := <-events
|
data := <-events
|
||||||
|
|
||||||
|
@ -201,7 +312,9 @@ func sessionEventHandler(session Session, events chan DataObject, bridge webBrid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) startSession(params DataObject, events chan DataObject, bridge webBridge) (Session, string) {
|
func (app *application) startSession(params DataObject, events chan DataObject,
|
||||||
|
bridge bridge, response chan string) (Session, string) {
|
||||||
|
|
||||||
if app.createContentFunc == nil {
|
if app.createContentFunc == nil {
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
@ -212,7 +325,10 @@ func (app *application) startSession(params DataObject, events chan DataObject,
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
app.sessions[session.ID()] = session
|
app.sessions[session.ID()] = sessionInfo{
|
||||||
|
session: session,
|
||||||
|
response: response,
|
||||||
|
}
|
||||||
|
|
||||||
answer := allocStringBuilder()
|
answer := allocStringBuilder()
|
||||||
defer freeStringBuilder(answer)
|
defer freeStringBuilder(answer)
|
||||||
|
@ -236,7 +352,7 @@ var apps = []*application{}
|
||||||
func StartApp(addr string, createContentFunc func(Session) SessionContent, params AppParams) {
|
func StartApp(addr string, createContentFunc func(Session) SessionContent, params AppParams) {
|
||||||
app := new(application)
|
app := new(application)
|
||||||
app.params = params
|
app.params = params
|
||||||
app.sessions = map[int]Session{}
|
app.sessions = map[int]sessionInfo{}
|
||||||
app.createContentFunc = createContentFunc
|
app.createContentFunc = createContentFunc
|
||||||
apps = append(apps, app)
|
apps = append(apps, app)
|
||||||
|
|
||||||
|
|
15
appWasm.go
15
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
|
||||||
bridge webBridge
|
bridge bridge
|
||||||
close chan DataObject
|
close chan DataObject
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,17 +44,10 @@ func (app *wasmApp) handleMessage(this js.Value, args []js.Value) any {
|
||||||
case "session-close":
|
case "session-close":
|
||||||
app.close <- obj
|
app.close <- obj
|
||||||
|
|
||||||
case "answer":
|
|
||||||
app.session.handleAnswer(obj)
|
|
||||||
|
|
||||||
case "imageLoaded":
|
|
||||||
app.session.imageManager().imageLoaded(obj, app.session)
|
|
||||||
|
|
||||||
case "imageError":
|
|
||||||
app.session.imageManager().imageLoadError(obj, app.session)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
app.session.handleEvent(command, obj)
|
if !app.session.handleAnswer(command, obj) {
|
||||||
|
app.session.handleEvent(command, obj)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
|
||||||
|
function sendMessage(message) {
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('POST', '/', true);
|
||||||
|
xhr.onreadystatechange = function() {
|
||||||
|
const script = this.responseText
|
||||||
|
if (script != "") {
|
||||||
|
window.eval(script)
|
||||||
|
//sendMessage("nop{session=" + sessionID +"}")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
xhr.send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function() {
|
||||||
|
sendMessage( sessionInfo() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
window.onload = function() {
|
||||||
|
socketUrl = document.location.protocol == "https:" ? "wss://" : "ws://"
|
||||||
|
socketUrl += document.location.hostname
|
||||||
|
const port = document.location.port
|
||||||
|
if (port) {
|
||||||
|
socketUrl += ":" + port
|
||||||
|
}
|
||||||
|
socketUrl += window.location.pathname + "ws"
|
||||||
|
|
||||||
|
socket = new WebSocket(socketUrl);
|
||||||
|
socket.onopen = socketOpen;
|
||||||
|
socket.onclose = socketClose;
|
||||||
|
socket.onerror = socketError;
|
||||||
|
socket.onmessage = function(event) {
|
||||||
|
window.execScript ? window.execScript(event.data) : window.eval(event.data);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function socketOpen() {
|
||||||
|
sendMessage( sessionInfo() );
|
||||||
|
}
|
||||||
|
|
||||||
|
function socketReopen() {
|
||||||
|
sendMessage( "reconnect{session=" + sessionID + "}" );
|
||||||
|
}
|
||||||
|
|
||||||
|
function socketReconnect() {
|
||||||
|
if (!socket) {
|
||||||
|
socket = new WebSocket(socketUrl);
|
||||||
|
socket.onopen = socketReopen;
|
||||||
|
socket.onclose = socketClose;
|
||||||
|
socket.onerror = socketError;
|
||||||
|
socket.onmessage = function(event) {
|
||||||
|
window.execScript ? window.execScript(event.data) : window.eval(event.data);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function socketClose(event) {
|
||||||
|
console.log("socket closed")
|
||||||
|
socket = null;
|
||||||
|
if (!event.wasClean && windowFocus) {
|
||||||
|
window.setTimeout(socketReconnect, 10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function socketError(error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onfocus = function(event) {
|
||||||
|
windowFocus = true
|
||||||
|
sendMessage( "session-resume{session=" + sessionID +"}" );
|
||||||
|
}
|
|
@ -1902,10 +1902,28 @@ function getPropertyValue(answerID, elementId, name) {
|
||||||
sendMessage('answer{answerID=' + answerID + ', value=""}')
|
sendMessage('answer{answerID=' + answerID + ', value=""}')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setStyles(styles) {
|
||||||
|
document.querySelector('style').textContent = styles
|
||||||
|
}
|
||||||
|
|
||||||
function appendStyles(styles) {
|
function appendStyles(styles) {
|
||||||
document.querySelector('style').textContent += styles
|
document.querySelector('style').textContent += styles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function appendAnimationCSS(css) {
|
||||||
|
let styles = document.getElementById('ruiAnimations');
|
||||||
|
if (styles) {
|
||||||
|
styles.textContent += css;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAnimationCSS(css) {
|
||||||
|
let styles = document.getElementById('ruiAnimations');
|
||||||
|
if (styles) {
|
||||||
|
styles.textContent = css;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getCanvasContext(elementId) {
|
function getCanvasContext(elementId) {
|
||||||
const canvas = document.getElementById(elementId)
|
const canvas = document.getElementById(elementId)
|
||||||
if (canvas) {
|
if (canvas) {
|
||||||
|
|
|
@ -38,9 +38,12 @@ type AppParams struct {
|
||||||
KeyFile string
|
KeyFile string
|
||||||
// Redirect80 - if true then the function of redirect from port 80 to 443 is created
|
// Redirect80 - if true then the function of redirect from port 80 to 443 is created
|
||||||
Redirect80 bool
|
Redirect80 bool
|
||||||
|
// NoSocket - if true then WebSockets will not be used and information exchange
|
||||||
|
// between the client and the server will be carried out only via http.
|
||||||
|
NoSocket bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStartPage(buffer *strings.Builder, params AppParams, addScripts string) {
|
func getStartPage(buffer *strings.Builder, params AppParams) {
|
||||||
buffer.WriteString(`<head>
|
buffer.WriteString(`<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>`)
|
<title>`)
|
||||||
|
@ -67,11 +70,7 @@ func getStartPage(buffer *strings.Builder, params AppParams, addScripts string)
|
||||||
buffer.WriteString(appStyles)
|
buffer.WriteString(appStyles)
|
||||||
buffer.WriteString(`</style>
|
buffer.WriteString(`</style>
|
||||||
<style id="ruiAnimations"></style>
|
<style id="ruiAnimations"></style>
|
||||||
<script>
|
<script src="/script.js"></script>
|
||||||
`)
|
|
||||||
buffer.WriteString(defaultScripts)
|
|
||||||
buffer.WriteString(addScripts)
|
|
||||||
buffer.WriteString(`</script>
|
|
||||||
</head>
|
</head>
|
||||||
<body id="body" onkeydown="keyDownEvent(this, event)">
|
<body id="body" onkeydown="keyDownEvent(this, event)">
|
||||||
<div class="ruiRoot" id="ruiRootView"></div>
|
<div class="ruiRoot" id="ruiRootView"></div>
|
||||||
|
|
1
image.go
1
image.go
|
@ -80,6 +80,7 @@ func (manager *imageManager) loadImage(url string, onLoaded func(Image), session
|
||||||
manager.images[url] = image
|
manager.images[url] = image
|
||||||
|
|
||||||
session.callFunc("loadImage", url)
|
session.callFunc("loadImage", url)
|
||||||
|
session.sendResponse()
|
||||||
return image
|
return image
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
70
session.go
70
session.go
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type webBridge interface {
|
type bridge 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
|
||||||
|
@ -16,10 +16,9 @@ type webBridge interface {
|
||||||
updateCSSProperty(htmlID, property, value string)
|
updateCSSProperty(htmlID, property, value string)
|
||||||
updateProperty(htmlID, property string, value any)
|
updateProperty(htmlID, property string, value any)
|
||||||
removeProperty(htmlID, property string)
|
removeProperty(htmlID, property string)
|
||||||
readMessage() (string, bool)
|
sendResponse()
|
||||||
writeMessage(text string) bool
|
setAnimationCSS(css string)
|
||||||
addAnimationCSS(css string)
|
appendAnimationCSS(css string)
|
||||||
clearAnimation()
|
|
||||||
canvasStart(htmlID string)
|
canvasStart(htmlID string)
|
||||||
callCanvasFunc(funcName string, args ...any)
|
callCanvasFunc(funcName string, args ...any)
|
||||||
callCanvasVarFunc(v any, funcName string, args ...any)
|
callCanvasVarFunc(v any, funcName string, args ...any)
|
||||||
|
@ -124,7 +123,7 @@ type Session interface {
|
||||||
nextViewID() string
|
nextViewID() string
|
||||||
styleProperty(styleTag, property string) any
|
styleProperty(styleTag, property string) any
|
||||||
|
|
||||||
setBridge(events chan DataObject, bridge webBridge)
|
setBridge(events chan DataObject, bridge bridge)
|
||||||
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)
|
||||||
|
@ -134,6 +133,7 @@ type Session interface {
|
||||||
removeProperty(htmlID, property string)
|
removeProperty(htmlID, property string)
|
||||||
startUpdateScript(htmlID string) bool
|
startUpdateScript(htmlID string) bool
|
||||||
finishUpdateScript(htmlID string)
|
finishUpdateScript(htmlID string)
|
||||||
|
sendResponse()
|
||||||
addAnimationCSS(css string)
|
addAnimationCSS(css string)
|
||||||
clearAnimation()
|
clearAnimation()
|
||||||
canvasStart(htmlID string)
|
canvasStart(htmlID string)
|
||||||
|
@ -145,7 +145,8 @@ type Session interface {
|
||||||
canvasFinish()
|
canvasFinish()
|
||||||
canvasTextMetrics(htmlID, font, text string) TextMetrics
|
canvasTextMetrics(htmlID, font, text string) TextMetrics
|
||||||
htmlPropertyValue(htmlID, name string) string
|
htmlPropertyValue(htmlID, name string) string
|
||||||
handleAnswer(data DataObject)
|
addToEventsQueue(data DataObject)
|
||||||
|
handleAnswer(command string, data DataObject) bool
|
||||||
handleRootSize(data DataObject)
|
handleRootSize(data DataObject)
|
||||||
handleResize(data DataObject)
|
handleResize(data DataObject)
|
||||||
handleEvent(command string, data DataObject)
|
handleEvent(command string, data DataObject)
|
||||||
|
@ -189,7 +190,7 @@ type sessionData struct {
|
||||||
ignoreUpdates bool
|
ignoreUpdates bool
|
||||||
popups *popupManager
|
popups *popupManager
|
||||||
images *imageManager
|
images *imageManager
|
||||||
bridge webBridge
|
bridge bridge
|
||||||
events chan DataObject
|
events chan DataObject
|
||||||
animationCounter int
|
animationCounter int
|
||||||
animationCSS string
|
animationCSS string
|
||||||
|
@ -237,7 +238,7 @@ func (session *sessionData) ID() int {
|
||||||
return session.sessionID
|
return session.sessionID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) setBridge(events chan DataObject, bridge webBridge) {
|
func (session *sessionData) setBridge(events chan DataObject, bridge bridge) {
|
||||||
session.events = events
|
session.events = events
|
||||||
session.bridge = bridge
|
session.bridge = bridge
|
||||||
}
|
}
|
||||||
|
@ -330,23 +331,19 @@ func (session *sessionData) updateTooltipConstants() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) reload() {
|
func (session *sessionData) reload() {
|
||||||
buffer := allocStringBuilder()
|
|
||||||
defer freeStringBuilder(buffer)
|
|
||||||
|
|
||||||
css := appStyles + session.getCurrentTheme().cssText(session) + session.animationCSS
|
css := appStyles + session.getCurrentTheme().cssText(session) + session.animationCSS
|
||||||
css = strings.ReplaceAll(css, "\n", `\n`)
|
session.bridge.callFunc("setStyles", css)
|
||||||
css = strings.ReplaceAll(css, "\t", `\t`)
|
|
||||||
buffer.WriteString(`document.querySelector('style').textContent = "`)
|
|
||||||
buffer.WriteString(css)
|
|
||||||
buffer.WriteString("\";\n")
|
|
||||||
|
|
||||||
if session.rootView != nil {
|
if session.rootView != nil {
|
||||||
buffer.WriteString(`document.getElementById('ruiRootView').innerHTML = '`)
|
buffer := allocStringBuilder()
|
||||||
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
viewHTML(session.rootView, buffer)
|
viewHTML(session.rootView, buffer)
|
||||||
buffer.WriteString("';\nscanElementsSize();")
|
session.bridge.updateInnerHTML("ruiRootView", buffer.String())
|
||||||
|
session.bridge.callFunc("scanElementsSize")
|
||||||
}
|
}
|
||||||
|
|
||||||
session.bridge.writeMessage(buffer.String())
|
|
||||||
session.updateTooltipConstants()
|
session.updateTooltipConstants()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,15 +444,21 @@ func (session *sessionData) finishUpdateScript(htmlID string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (session *sessionData) sendResponse() {
|
||||||
|
if session.bridge != nil {
|
||||||
|
session.bridge.sendResponse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (session *sessionData) addAnimationCSS(css string) {
|
func (session *sessionData) addAnimationCSS(css string) {
|
||||||
if session.bridge != nil {
|
if session.bridge != nil {
|
||||||
session.bridge.addAnimationCSS(css)
|
session.bridge.appendAnimationCSS(css)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) clearAnimation() {
|
func (session *sessionData) clearAnimation() {
|
||||||
if session.bridge != nil {
|
if session.bridge != nil {
|
||||||
session.bridge.clearAnimation()
|
session.bridge.setAnimationCSS("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,8 +523,23 @@ func (session *sessionData) htmlPropertyValue(htmlID, name string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) handleAnswer(data DataObject) {
|
func (session *sessionData) handleAnswer(command string, data DataObject) bool {
|
||||||
session.bridge.answerReceived(data)
|
switch command {
|
||||||
|
case "answer":
|
||||||
|
session.bridge.answerReceived(data)
|
||||||
|
|
||||||
|
case "imageLoaded":
|
||||||
|
session.imageManager().imageLoaded(data)
|
||||||
|
|
||||||
|
case "imageError":
|
||||||
|
session.imageManager().imageLoadError(data)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
session.bridge.sendResponse()
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) handleRootSize(data DataObject) {
|
func (session *sessionData) handleRootSize(data DataObject) {
|
||||||
|
@ -672,6 +690,8 @@ func (session *sessionData) handleEvent(command string, data DataObject) {
|
||||||
ErrorLog(`"id" property not found. Event: ` + command)
|
ErrorLog(`"id" property not found. Event: ` + command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session.bridge.sendResponse()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) hotKey(event KeyEvent) {
|
func (session *sessionData) hotKey(event KeyEvent) {
|
||||||
|
@ -769,3 +789,7 @@ func (session *sessionData) RemoveAllClientItems() {
|
||||||
session.clientStorage = map[string]string{}
|
session.clientStorage = map[string]string{}
|
||||||
session.bridge.callFunc("localStorageClear")
|
session.bridge.callFunc("localStorageClear")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (session *sessionData) addToEventsQueue(data DataObject) {
|
||||||
|
session.events <- data
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ type wasmBridge struct {
|
||||||
closeEvent chan DataObject
|
closeEvent chan DataObject
|
||||||
}
|
}
|
||||||
|
|
||||||
func createWasmBridge(close chan DataObject) webBridge {
|
func createWasmBridge(close chan DataObject) bridge {
|
||||||
bridge := new(wasmBridge)
|
bridge := new(wasmBridge)
|
||||||
bridge.answerID = 1
|
bridge.answerID = 1
|
||||||
bridge.answer = make(map[int]chan DataObject)
|
bridge.answer = make(map[int]chan DataObject)
|
||||||
|
@ -102,10 +102,6 @@ func (bridge *wasmBridge) close() {
|
||||||
bridge.closeEvent <- NewDataObject("close")
|
bridge.closeEvent <- NewDataObject("close")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wasmBridge) readMessage() (string, bool) {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bridge *wasmBridge) writeMessage(script string) bool {
|
func (bridge *wasmBridge) writeMessage(script string) bool {
|
||||||
if ProtocolInDebugLog {
|
if ProtocolInDebugLog {
|
||||||
DebugLog("Run script:")
|
DebugLog("Run script:")
|
||||||
|
@ -118,21 +114,24 @@ func (bridge *wasmBridge) writeMessage(script string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wasmBridge) addAnimationCSS(css string) {
|
func (bridge *wasmBridge) prepareCSS(css string) string {
|
||||||
css = strings.ReplaceAll(css, `\t`, "\t")
|
css = strings.ReplaceAll(css, `\t`, "\t")
|
||||||
css = strings.ReplaceAll(css, `\n`, "\n")
|
css = strings.ReplaceAll(css, `\n`, "\n")
|
||||||
css = strings.ReplaceAll(css, `\'`, "'")
|
css = strings.ReplaceAll(css, `\'`, "'")
|
||||||
css = strings.ReplaceAll(css, `\"`, "\"")
|
css = strings.ReplaceAll(css, `\"`, "\"")
|
||||||
css = strings.ReplaceAll(css, `\\`, "\\")
|
css = strings.ReplaceAll(css, `\\`, "\\")
|
||||||
|
return css
|
||||||
styles := js.Global().Get("document").Call("getElementById", "ruiAnimations")
|
|
||||||
content := styles.Get("textContent").String()
|
|
||||||
styles.Set("textContent", content+"\n"+css)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wasmBridge) clearAnimation() {
|
func (bridge *wasmBridge) appendAnimationCSS(css string) {
|
||||||
styles := js.Global().Get("document").Call("getElementById", "ruiAnimations")
|
styles := js.Global().Get("document").Call("getElementById", "ruiAnimations")
|
||||||
styles.Set("textContent", "")
|
content := styles.Get("textContent").String()
|
||||||
|
styles.Set("textContent", content+"\n"+bridge.prepareCSS(css))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) setAnimationCSS(css string) {
|
||||||
|
styles := js.Global().Get("document").Call("getElementById", "ruiAnimations")
|
||||||
|
styles.Set("textContent", bridge.prepareCSS(css))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wasmBridge) canvasStart(htmlID string) {
|
func (bridge *wasmBridge) canvasStart(htmlID string) {
|
||||||
|
@ -276,3 +275,6 @@ func (bridge *wasmBridge) answerReceived(answer DataObject) {
|
||||||
func (bridge *wasmBridge) remoteAddr() string {
|
func (bridge *wasmBridge) remoteAddr() string {
|
||||||
return "localhost"
|
return "localhost"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) sendResponse() {
|
||||||
|
}
|
||||||
|
|
327
webBridge.go
327
webBridge.go
|
@ -12,17 +12,30 @@ import (
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type webBridge struct {
|
||||||
|
answer map[int]chan DataObject
|
||||||
|
answerID int
|
||||||
|
answerMutex sync.Mutex
|
||||||
|
writeMutex sync.Mutex
|
||||||
|
closed bool
|
||||||
|
canvasBuffer strings.Builder
|
||||||
|
canvasVarNumber int
|
||||||
|
updateScripts map[string]*strings.Builder
|
||||||
|
writeMessage func(string) bool
|
||||||
|
callFuncImmediately func(funcName string, args ...any) bool
|
||||||
|
}
|
||||||
|
|
||||||
type wsBridge struct {
|
type wsBridge struct {
|
||||||
conn *websocket.Conn
|
webBridge
|
||||||
answer map[int]chan DataObject
|
conn *websocket.Conn
|
||||||
answerID int
|
}
|
||||||
answerMutex sync.Mutex
|
|
||||||
writeMutex sync.Mutex
|
type httpBridge struct {
|
||||||
closed bool
|
webBridge
|
||||||
buffer strings.Builder
|
responseBuffer strings.Builder
|
||||||
canvasBuffer strings.Builder
|
response chan string
|
||||||
canvasVarNumber int
|
remoteAddress string
|
||||||
updateScripts map[string]*strings.Builder
|
//conn *websocket.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
type canvasVar struct {
|
type canvasVar struct {
|
||||||
|
@ -34,7 +47,7 @@ var upgrader = websocket.Upgrader{
|
||||||
WriteBufferSize: 8096,
|
WriteBufferSize: 8096,
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateSocketBridge(w http.ResponseWriter, req *http.Request) webBridge {
|
func createSocketBridge(w http.ResponseWriter, req *http.Request) *wsBridge {
|
||||||
conn, err := upgrader.Upgrade(w, req, nil)
|
conn, err := upgrader.Upgrade(w, req, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorLog(err.Error())
|
ErrorLog(err.Error())
|
||||||
|
@ -42,42 +55,84 @@ func CreateSocketBridge(w http.ResponseWriter, req *http.Request) webBridge {
|
||||||
}
|
}
|
||||||
|
|
||||||
bridge := new(wsBridge)
|
bridge := new(wsBridge)
|
||||||
bridge.answerID = 1
|
bridge.initBridge()
|
||||||
bridge.answer = make(map[int]chan DataObject)
|
|
||||||
bridge.conn = conn
|
bridge.conn = conn
|
||||||
bridge.closed = false
|
bridge.writeMessage = func(script string) bool {
|
||||||
bridge.updateScripts = map[string]*strings.Builder{}
|
if ProtocolInDebugLog {
|
||||||
|
DebugLog("🖥️ <- " + script)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bridge.conn == nil {
|
||||||
|
ErrorLog("No connection")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
bridge.writeMutex.Lock()
|
||||||
|
err := bridge.conn.WriteMessage(websocket.TextMessage, []byte(script))
|
||||||
|
bridge.writeMutex.Unlock()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
bridge.callFuncImmediately = bridge.callFunc
|
||||||
return bridge
|
return bridge
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) close() {
|
func createHttpBridge(req *http.Request) *httpBridge {
|
||||||
bridge.closed = true
|
bridge := new(httpBridge)
|
||||||
defer bridge.conn.Close()
|
bridge.initBridge()
|
||||||
bridge.conn = nil
|
bridge.response = make(chan string, 10)
|
||||||
|
bridge.writeMessage = func(script string) bool {
|
||||||
|
if script != "" {
|
||||||
|
if ProtocolInDebugLog {
|
||||||
|
DebugLog(script)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bridge.responseBuffer.Len() > 0 {
|
||||||
|
bridge.responseBuffer.WriteRune('\n')
|
||||||
|
}
|
||||||
|
bridge.responseBuffer.WriteString(script)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
bridge.callFuncImmediately = bridge.callImmediately
|
||||||
|
bridge.remoteAddress = req.RemoteAddr
|
||||||
|
return bridge
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) startUpdateScript(htmlID string) bool {
|
func (bridge *webBridge) initBridge() {
|
||||||
|
bridge.answerID = 1
|
||||||
|
bridge.answer = make(map[int]chan DataObject)
|
||||||
|
bridge.closed = false
|
||||||
|
bridge.updateScripts = map[string]*strings.Builder{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *webBridge) startUpdateScript(htmlID string) bool {
|
||||||
if _, ok := bridge.updateScripts[htmlID]; ok {
|
if _, ok := bridge.updateScripts[htmlID]; ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
bridge.updateScripts[htmlID] = buffer
|
bridge.updateScripts[htmlID] = buffer
|
||||||
buffer.WriteString("let element = document.getElementById('")
|
buffer.WriteString("{\nlet element = document.getElementById('")
|
||||||
buffer.WriteString(htmlID)
|
buffer.WriteString(htmlID)
|
||||||
buffer.WriteString("');\nif (element) {\n")
|
buffer.WriteString("');\nif (element) {\n")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) finishUpdateScript(htmlID string) {
|
func (bridge *webBridge) finishUpdateScript(htmlID string) {
|
||||||
if buffer, ok := bridge.updateScripts[htmlID]; ok {
|
if buffer, ok := bridge.updateScripts[htmlID]; ok {
|
||||||
buffer.WriteString("scanElementsSize();\n}\n")
|
buffer.WriteString("scanElementsSize();\n}\n}\n")
|
||||||
bridge.writeMessage(buffer.String())
|
bridge.writeMessage(buffer.String())
|
||||||
|
|
||||||
freeStringBuilder(buffer)
|
freeStringBuilder(buffer)
|
||||||
delete(bridge.updateScripts, htmlID)
|
delete(bridge.updateScripts, htmlID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) argToString(arg any) (string, bool) {
|
func (bridge *webBridge) argToString(arg any) (string, bool) {
|
||||||
switch arg := arg.(type) {
|
switch arg := arg.(type) {
|
||||||
case string:
|
case string:
|
||||||
arg = strings.ReplaceAll(arg, "\\", `\\`)
|
arg = strings.ReplaceAll(arg, "\\", `\\`)
|
||||||
|
@ -152,47 +207,44 @@ func (bridge *wsBridge) argToString(arg any) (string, bool) {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) callFunc(funcName string, args ...any) bool {
|
func (bridge *webBridge) callFuncScript(funcName string, args ...any) (string, bool) {
|
||||||
bridge.buffer.Reset()
|
buffer := allocStringBuilder()
|
||||||
bridge.buffer.WriteString(funcName)
|
defer freeStringBuilder(buffer)
|
||||||
bridge.buffer.WriteRune('(')
|
|
||||||
|
buffer.WriteString(funcName)
|
||||||
|
buffer.WriteRune('(')
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
argText, ok := bridge.argToString(arg)
|
argText, ok := bridge.argToString(arg)
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
bridge.buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
bridge.buffer.WriteString(argText)
|
buffer.WriteString(argText)
|
||||||
}
|
}
|
||||||
bridge.buffer.WriteString(");")
|
buffer.WriteString(");")
|
||||||
|
|
||||||
funcText := bridge.buffer.String()
|
return buffer.String(), true
|
||||||
if ProtocolInDebugLog {
|
|
||||||
DebugLog("Run func: " + funcText)
|
|
||||||
}
|
|
||||||
|
|
||||||
bridge.writeMutex.Lock()
|
|
||||||
err := bridge.conn.WriteMessage(websocket.TextMessage, []byte(funcText))
|
|
||||||
bridge.writeMutex.Unlock()
|
|
||||||
if err != nil {
|
|
||||||
ErrorLog(err.Error())
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) updateInnerHTML(htmlID, html string) {
|
func (bridge *webBridge) callFunc(funcName string, args ...any) bool {
|
||||||
|
if funcText, ok := bridge.callFuncScript(funcName, args...); ok {
|
||||||
|
return bridge.writeMessage(funcText)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *webBridge) updateInnerHTML(htmlID, html string) {
|
||||||
bridge.callFunc("updateInnerHTML", htmlID, html)
|
bridge.callFunc("updateInnerHTML", htmlID, html)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) appendToInnerHTML(htmlID, html string) {
|
func (bridge *webBridge) appendToInnerHTML(htmlID, html string) {
|
||||||
bridge.callFunc("appendToInnerHTML", htmlID, html)
|
bridge.callFunc("appendToInnerHTML", htmlID, html)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) updateCSSProperty(htmlID, property, value string) {
|
func (bridge *webBridge) updateCSSProperty(htmlID, property, value string) {
|
||||||
if buffer, ok := bridge.updateScripts[htmlID]; ok {
|
if buffer, ok := bridge.updateScripts[htmlID]; ok {
|
||||||
buffer.WriteString(`element.style['`)
|
buffer.WriteString(`element.style['`)
|
||||||
buffer.WriteString(property)
|
buffer.WriteString(property)
|
||||||
|
@ -204,7 +256,7 @@ func (bridge *wsBridge) updateCSSProperty(htmlID, property, value string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) updateProperty(htmlID, property string, value any) {
|
func (bridge *webBridge) updateProperty(htmlID, property string, value any) {
|
||||||
if buffer, ok := bridge.updateScripts[htmlID]; ok {
|
if buffer, ok := bridge.updateScripts[htmlID]; ok {
|
||||||
if val, ok := bridge.argToString(value); ok {
|
if val, ok := bridge.argToString(value); ok {
|
||||||
buffer.WriteString(`element.setAttribute('`)
|
buffer.WriteString(`element.setAttribute('`)
|
||||||
|
@ -218,7 +270,7 @@ func (bridge *wsBridge) updateProperty(htmlID, property string, value any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) removeProperty(htmlID, property string) {
|
func (bridge *webBridge) removeProperty(htmlID, property string) {
|
||||||
if buffer, ok := bridge.updateScripts[htmlID]; ok {
|
if buffer, ok := bridge.updateScripts[htmlID]; ok {
|
||||||
buffer.WriteString(`if (element.hasAttribute('`)
|
buffer.WriteString(`if (element.hasAttribute('`)
|
||||||
buffer.WriteString(property)
|
buffer.WriteString(property)
|
||||||
|
@ -230,28 +282,34 @@ func (bridge *wsBridge) removeProperty(htmlID, property string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) addAnimationCSS(css string) {
|
func (bridge *webBridge) appendAnimationCSS(css string) {
|
||||||
bridge.writeMessage(`var styles = document.getElementById('ruiAnimations');
|
//bridge.callFunc("appendAnimationCSS", css)
|
||||||
if (styles) {
|
bridge.writeMessage(`{
|
||||||
styles.textContent += '` + css + `';
|
let styles = document.getElementById('ruiAnimations');
|
||||||
|
if (styles) {
|
||||||
|
styles.textContent += '` + css + `';
|
||||||
|
}
|
||||||
}`)
|
}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) clearAnimation() {
|
func (bridge *webBridge) setAnimationCSS(css string) {
|
||||||
bridge.writeMessage(`var styles = document.getElementById('ruiAnimations');
|
//bridge.callFunc("setAnimationCSS", css)
|
||||||
if (styles) {
|
bridge.writeMessage(`{
|
||||||
styles.textContent = '';
|
let styles = document.getElementById('ruiAnimations');
|
||||||
|
if (styles) {
|
||||||
|
styles.textContent = '` + css + `';
|
||||||
|
}
|
||||||
}`)
|
}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) canvasStart(htmlID string) {
|
func (bridge *webBridge) canvasStart(htmlID string) {
|
||||||
bridge.canvasBuffer.Reset()
|
bridge.canvasBuffer.Reset()
|
||||||
bridge.canvasBuffer.WriteString(`const ctx = getCanvasContext('`)
|
bridge.canvasBuffer.WriteString("{\nconst ctx = getCanvasContext('")
|
||||||
bridge.canvasBuffer.WriteString(htmlID)
|
bridge.canvasBuffer.WriteString(htmlID)
|
||||||
bridge.canvasBuffer.WriteString(`');`)
|
bridge.canvasBuffer.WriteString(`');`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) callCanvasFunc(funcName string, args ...any) {
|
func (bridge *webBridge) callCanvasFunc(funcName string, args ...any) {
|
||||||
bridge.canvasBuffer.WriteString("\nctx.")
|
bridge.canvasBuffer.WriteString("\nctx.")
|
||||||
bridge.canvasBuffer.WriteString(funcName)
|
bridge.canvasBuffer.WriteString(funcName)
|
||||||
bridge.canvasBuffer.WriteRune('(')
|
bridge.canvasBuffer.WriteRune('(')
|
||||||
|
@ -265,7 +323,7 @@ func (bridge *wsBridge) callCanvasFunc(funcName string, args ...any) {
|
||||||
bridge.canvasBuffer.WriteString(");")
|
bridge.canvasBuffer.WriteString(");")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) updateCanvasProperty(property string, value any) {
|
func (bridge *webBridge) updateCanvasProperty(property string, value any) {
|
||||||
bridge.canvasBuffer.WriteString("\nctx.")
|
bridge.canvasBuffer.WriteString("\nctx.")
|
||||||
bridge.canvasBuffer.WriteString(property)
|
bridge.canvasBuffer.WriteString(property)
|
||||||
bridge.canvasBuffer.WriteString(" = ")
|
bridge.canvasBuffer.WriteString(" = ")
|
||||||
|
@ -274,7 +332,7 @@ func (bridge *wsBridge) updateCanvasProperty(property string, value any) {
|
||||||
bridge.canvasBuffer.WriteString(";")
|
bridge.canvasBuffer.WriteString(";")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) createCanvasVar(funcName string, args ...any) any {
|
func (bridge *webBridge) createCanvasVar(funcName string, args ...any) any {
|
||||||
bridge.canvasVarNumber++
|
bridge.canvasVarNumber++
|
||||||
result := canvasVar{name: fmt.Sprintf("v%d", bridge.canvasVarNumber)}
|
result := canvasVar{name: fmt.Sprintf("v%d", bridge.canvasVarNumber)}
|
||||||
bridge.canvasBuffer.WriteString("\nlet ")
|
bridge.canvasBuffer.WriteString("\nlet ")
|
||||||
|
@ -293,7 +351,7 @@ func (bridge *wsBridge) createCanvasVar(funcName string, args ...any) any {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) callCanvasVarFunc(v any, funcName string, args ...any) {
|
func (bridge *webBridge) callCanvasVarFunc(v any, funcName string, args ...any) {
|
||||||
varName, ok := v.(canvasVar)
|
varName, ok := v.(canvasVar)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
|
@ -313,7 +371,7 @@ func (bridge *wsBridge) callCanvasVarFunc(v any, funcName string, args ...any) {
|
||||||
bridge.canvasBuffer.WriteString(");")
|
bridge.canvasBuffer.WriteString(");")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) callCanvasImageFunc(url string, property string, funcName string, args ...any) {
|
func (bridge *webBridge) callCanvasImageFunc(url string, property string, funcName string, args ...any) {
|
||||||
|
|
||||||
bridge.canvasBuffer.WriteString("\nimg = images.get('")
|
bridge.canvasBuffer.WriteString("\nimg = images.get('")
|
||||||
bridge.canvasBuffer.WriteString(url)
|
bridge.canvasBuffer.WriteString(url)
|
||||||
|
@ -334,56 +392,12 @@ func (bridge *wsBridge) callCanvasImageFunc(url string, property string, funcNam
|
||||||
bridge.canvasBuffer.WriteString(");\n}")
|
bridge.canvasBuffer.WriteString(");\n}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) canvasFinish() {
|
func (bridge *webBridge) canvasFinish() {
|
||||||
bridge.canvasBuffer.WriteString("\n")
|
bridge.canvasBuffer.WriteString("\n}\n")
|
||||||
script := bridge.canvasBuffer.String()
|
bridge.writeMessage(bridge.canvasBuffer.String())
|
||||||
if ProtocolInDebugLog {
|
|
||||||
DebugLog("Run script:")
|
|
||||||
DebugLog(script)
|
|
||||||
}
|
|
||||||
bridge.writeMutex.Lock()
|
|
||||||
if bridge.conn == nil {
|
|
||||||
ErrorLog("No connection")
|
|
||||||
} else if err := bridge.conn.WriteMessage(websocket.TextMessage, []byte(script)); err != nil {
|
|
||||||
ErrorLog(err.Error())
|
|
||||||
}
|
|
||||||
bridge.writeMutex.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) readMessage() (string, bool) {
|
func (bridge *webBridge) removeValue(funcName, htmlID string, args ...string) (DataObject, 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
|
|
||||||
}
|
|
||||||
bridge.writeMutex.Lock()
|
|
||||||
err := bridge.conn.WriteMessage(websocket.TextMessage, []byte(script))
|
|
||||||
bridge.writeMutex.Unlock()
|
|
||||||
if err != nil {
|
|
||||||
ErrorLog(err.Error())
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bridge *wsBridge) canvasTextMetrics(htmlID, font, text string) TextMetrics {
|
|
||||||
result := TextMetrics{}
|
|
||||||
|
|
||||||
bridge.answerMutex.Lock()
|
bridge.answerMutex.Lock()
|
||||||
answerID := bridge.answerID
|
answerID := bridge.answerID
|
||||||
bridge.answerID++
|
bridge.answerID++
|
||||||
|
@ -392,36 +406,40 @@ func (bridge *wsBridge) canvasTextMetrics(htmlID, font, text string) TextMetrics
|
||||||
answer := make(chan DataObject)
|
answer := make(chan DataObject)
|
||||||
bridge.answer[answerID] = answer
|
bridge.answer[answerID] = answer
|
||||||
|
|
||||||
if bridge.callFunc("canvasTextMetrics", answerID, htmlID, font, text) {
|
funcArgs := []any{answerID, htmlID}
|
||||||
data := <-answer
|
for _, arg := range args {
|
||||||
result.Width = dataFloatProperty(data, "width")
|
funcArgs = append(funcArgs, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var result DataObject = nil
|
||||||
|
ok := bridge.callFuncImmediately(funcName, funcArgs...)
|
||||||
|
if ok {
|
||||||
|
result = <-answer
|
||||||
|
}
|
||||||
|
|
||||||
|
close(answer)
|
||||||
delete(bridge.answer, answerID)
|
delete(bridge.answer, answerID)
|
||||||
|
return result, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *webBridge) canvasTextMetrics(htmlID, font, text string) TextMetrics {
|
||||||
|
result := TextMetrics{}
|
||||||
|
if data, ok := bridge.removeValue("canvasTextMetrics", htmlID, font, text); ok {
|
||||||
|
result.Width = dataFloatProperty(data, "width")
|
||||||
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) htmlPropertyValue(htmlID, name string) string {
|
func (bridge *webBridge) htmlPropertyValue(htmlID, name string) string {
|
||||||
bridge.answerMutex.Lock()
|
if data, ok := bridge.removeValue("getPropertyValue", htmlID, name); ok {
|
||||||
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 {
|
if value, ok := data.PropertyValue("value"); ok {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(bridge.answer, answerID)
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) answerReceived(answer DataObject) {
|
func (bridge *webBridge) answerReceived(answer DataObject) {
|
||||||
if text, ok := answer.PropertyValue("answerID"); ok {
|
if text, ok := answer.PropertyValue("answerID"); ok {
|
||||||
if id, err := strconv.Atoi(text); err == nil {
|
if id, err := strconv.Atoi(text); err == nil {
|
||||||
if chanel, ok := bridge.answer[id]; ok {
|
if chanel, ok := bridge.answer[id]; ok {
|
||||||
|
@ -438,6 +456,55 @@ func (bridge *wsBridge) answerReceived(answer DataObject) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bridge *wsBridge) close() {
|
||||||
|
bridge.closed = true
|
||||||
|
defer bridge.conn.Close()
|
||||||
|
bridge.conn = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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) sendResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
func (bridge *wsBridge) remoteAddr() string {
|
func (bridge *wsBridge) remoteAddr() string {
|
||||||
return bridge.conn.RemoteAddr().String()
|
return bridge.conn.RemoteAddr().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bridge *httpBridge) close() {
|
||||||
|
bridge.closed = true
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *httpBridge) callImmediately(funcName string, args ...any) bool {
|
||||||
|
if funcText, ok := bridge.callFuncScript(funcName, args...); ok {
|
||||||
|
if ProtocolInDebugLog {
|
||||||
|
DebugLog("Run func: " + funcText)
|
||||||
|
}
|
||||||
|
bridge.response <- funcText
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *httpBridge) sendResponse() {
|
||||||
|
bridge.writeMutex.Lock()
|
||||||
|
text := bridge.responseBuffer.String()
|
||||||
|
bridge.responseBuffer.Reset()
|
||||||
|
bridge.writeMutex.Unlock()
|
||||||
|
bridge.response <- text
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bridge *httpBridge) remoteAddr() string {
|
||||||
|
return bridge.remoteAddress
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue