mirror of https://github.com/anoshenko/rui.git
Fixing and optimisation
This commit is contained in:
parent
938432d738
commit
fb5582892e
138
appServer.go
138
appServer.go
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -43,6 +44,7 @@ type application struct {
|
||||||
params AppParams
|
params AppParams
|
||||||
createContentFunc func(Session) SessionContent
|
createContentFunc func(Session) SessionContent
|
||||||
sessions map[int]sessionInfo
|
sessions map[int]sessionInfo
|
||||||
|
usedSessionIds []int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) getStartPage() string {
|
func (app *application) getStartPage() string {
|
||||||
|
|
@ -50,7 +52,7 @@ 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)
|
getStartPage(buffer, app.nextSessionID(), app.params)
|
||||||
buffer.WriteString("\n</html>")
|
buffer.WriteString("\n</html>")
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
@ -80,15 +82,24 @@ func (app *application) Finish() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) nextSessionID() int {
|
func (app *application) getCreateContentFunc() func(Session) SessionContent {
|
||||||
n := rand.Intn(0x7FFFFFFE) + 1
|
return app.createContentFunc
|
||||||
_, ok := app.sessions[n]
|
|
||||||
for ok {
|
|
||||||
n = rand.Intn(0x7FFFFFFE) + 1
|
|
||||||
_, ok = app.sessions[n]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *application) nextSessionID() int {
|
||||||
|
if app.usedSessionIds == nil {
|
||||||
|
app.usedSessionIds = []int{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
n := rand.Intn(0x7FFFFFFE) + 1
|
||||||
|
if !slices.Contains(app.usedSessionIds, n) {
|
||||||
|
app.usedSessionIds = append(app.usedSessionIds, n)
|
||||||
|
slices.Sort(app.usedSessionIds)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (app *application) removeSession(id int) {
|
func (app *application) removeSession(id int) {
|
||||||
if info, ok := app.sessions[id]; ok {
|
if info, ok := app.sessions[id]; ok {
|
||||||
|
|
@ -166,9 +177,13 @@ func getSessionIDCookie(req *http.Request) (int, error) {
|
||||||
|
|
||||||
func (app *application) postHandler(w http.ResponseWriter, req *http.Request) {
|
func (app *application) postHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
if reqBody, err := io.ReadAll(req.Body); err == nil {
|
reqBody, err := io.ReadAll(req.Body)
|
||||||
message := string(reqBody)
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
message := string(reqBody)
|
||||||
if ProtocolInDebugLog {
|
if ProtocolInDebugLog {
|
||||||
DebugLog(message)
|
DebugLog(message)
|
||||||
}
|
}
|
||||||
|
|
@ -179,44 +194,44 @@ func (app *application) postHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sessionID, ok := getSessionID(obj)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var session Session = nil
|
var session Session = nil
|
||||||
var response chan string = nil
|
var response chan string = nil
|
||||||
|
if info, ok := app.sessions[sessionID]; ok && info.response != 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
|
response = info.response
|
||||||
session = info.session
|
session = info.session
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
command := obj.Tag()
|
command := obj.Tag()
|
||||||
startSession := false
|
|
||||||
|
|
||||||
if session == nil || command == "startSession" {
|
if session == nil || command == "startSession" {
|
||||||
events := make(chan DataObject, 1024)
|
events := make(chan DataObject, 1024)
|
||||||
bridge := createHttpBridge(req)
|
bridge := createHttpBridge(req)
|
||||||
response = bridge.response
|
response = bridge.response
|
||||||
answer := ""
|
|
||||||
session, answer = app.startSession(obj, events, bridge, response)
|
|
||||||
|
|
||||||
bridge.writeMessage(answer)
|
session = app.createSession(obj, events, bridge, response)
|
||||||
session.onStart()
|
if session == nil {
|
||||||
if command == "session-resume" {
|
return
|
||||||
session.onResume()
|
|
||||||
}
|
}
|
||||||
bridge.sendResponse()
|
|
||||||
|
|
||||||
setSessionIDCookie(w, session.ID())
|
|
||||||
startSession = true
|
|
||||||
|
|
||||||
go sessionEventHandler(session, events, bridge)
|
go sessionEventHandler(session, events, bridge)
|
||||||
|
|
||||||
|
start := func() {
|
||||||
|
startSession(session, app.createContentFunc)
|
||||||
|
bridge.sendResponse()
|
||||||
|
}
|
||||||
|
go start()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !startSession {
|
|
||||||
switch command {
|
switch command {
|
||||||
|
|
||||||
|
case "startSession":
|
||||||
|
// do nothing
|
||||||
|
|
||||||
case "nop":
|
case "nop":
|
||||||
session.sendResponse()
|
session.sendResponse()
|
||||||
|
|
||||||
|
|
@ -230,13 +245,27 @@ func (app *application) postHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
session.addToEventsQueue(obj)
|
session.addToEventsQueue(obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
io.WriteString(w, <-response)
|
io.WriteString(w, <-response)
|
||||||
for len(response) > 0 {
|
for len(response) > 0 {
|
||||||
io.WriteString(w, <-response)
|
io.WriteString(w, <-response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getSessionID(obj DataObject) (int, bool) {
|
||||||
|
sessionText, ok := obj.PropertyValue("session")
|
||||||
|
if !ok {
|
||||||
|
ErrorLog(`"session" key not found`)
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionID, err := strconv.Atoi(sessionText)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(`"session" key text strconv.Atoi error: ` + err.Error())
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return sessionID, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) socketReader(bridge *wsBridge) {
|
func (app *application) socketReader(bridge *wsBridge) {
|
||||||
|
|
@ -262,19 +291,14 @@ func (app *application) socketReader(bridge *wsBridge) {
|
||||||
|
|
||||||
switch command := obj.Tag(); command {
|
switch command := obj.Tag(); command {
|
||||||
case "startSession":
|
case "startSession":
|
||||||
answer := ""
|
if session = app.createSession(obj, events, bridge, nil); session != nil {
|
||||||
if session, answer = app.startSession(obj, events, bridge, nil); session != nil {
|
go startSession(session, app.createContentFunc)
|
||||||
if !bridge.writeMessage(answer) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
session.onStart()
|
|
||||||
go sessionEventHandler(session, events, bridge)
|
go sessionEventHandler(session, events, bridge)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "reconnect":
|
case "reconnect":
|
||||||
session = nil
|
session = nil
|
||||||
if sessionText, ok := obj.PropertyValue("session"); ok {
|
if sessionID, ok := getSessionID(obj); ok {
|
||||||
if sessionID, err := strconv.Atoi(sessionText); err == nil {
|
|
||||||
if info, ok := app.sessions[sessionID]; ok {
|
if info, ok := app.sessions[sessionID]; ok {
|
||||||
session = info.session
|
session = info.session
|
||||||
session.setBridge(events, bridge)
|
session.setBridge(events, bridge)
|
||||||
|
|
@ -284,11 +308,6 @@ func (app *application) socketReader(bridge *wsBridge) {
|
||||||
} else {
|
} else {
|
||||||
DebugLogF("Session #%d not exists", sessionID)
|
DebugLogF("Session #%d not exists", sessionID)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ErrorLog(`strconv.Atoi(sessionText) error: ` + err.Error())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ErrorLog(`"session" key not found`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if session == nil {
|
if session == nil {
|
||||||
|
|
@ -327,37 +346,42 @@ func sessionEventHandler(session Session, events chan DataObject, bridge bridge)
|
||||||
session.onFinish()
|
session.onFinish()
|
||||||
session.App().removeSession(session.ID())
|
session.App().removeSession(session.ID())
|
||||||
bridge.close()
|
bridge.close()
|
||||||
|
return
|
||||||
|
|
||||||
default:
|
default:
|
||||||
session.handleEvent(command, data)
|
go session.handleEvent(command, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) startSession(params DataObject, events chan DataObject,
|
func (app *application) createSession(params DataObject, events chan DataObject,
|
||||||
bridge bridge, response chan string) (Session, string) {
|
bridge bridge, response chan string) Session {
|
||||||
|
|
||||||
if app.createContentFunc == nil {
|
sessionID, ok := getSessionID(params)
|
||||||
return nil, ""
|
if !ok || app.createContentFunc == nil {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
session := newSession(app, app.nextSessionID(), "", params)
|
session := newSession(app, sessionID, "", params)
|
||||||
session.setBridge(events, bridge)
|
session.setBridge(events, bridge)
|
||||||
if !session.setContent(app.createContentFunc(session)) {
|
|
||||||
return nil, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
app.sessions[session.ID()] = sessionInfo{
|
app.sessions[sessionID] = sessionInfo{
|
||||||
session: session,
|
session: session,
|
||||||
response: response,
|
response: response,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
func startSession(session Session, createContentFunc func(Session) SessionContent) {
|
||||||
|
|
||||||
|
if !session.setContent(createContentFunc(session)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
answer := allocStringBuilder()
|
answer := allocStringBuilder()
|
||||||
defer freeStringBuilder(answer)
|
defer freeStringBuilder(answer)
|
||||||
|
|
||||||
answer.WriteString("sessionID = '")
|
|
||||||
answer.WriteString(strconv.Itoa(session.ID()))
|
|
||||||
answer.WriteString("';\n")
|
|
||||||
session.writeInitScript(answer)
|
session.writeInitScript(answer)
|
||||||
answerText := answer.String()
|
answerText := answer.String()
|
||||||
|
|
||||||
|
|
@ -365,7 +389,9 @@ func (app *application) startSession(params DataObject, events chan DataObject,
|
||||||
DebugLog("Start session:")
|
DebugLog("Start session:")
|
||||||
DebugLog(answerText)
|
DebugLog(answerText)
|
||||||
}
|
}
|
||||||
return session, answerText
|
|
||||||
|
session.writeScript(answerText)
|
||||||
|
session.onStart()
|
||||||
}
|
}
|
||||||
|
|
||||||
var apps = []*application{}
|
var apps = []*application{}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
let sessionID = "0"
|
//let sessionID = "0"
|
||||||
let windowFocus = true
|
let windowFocus = true
|
||||||
|
|
||||||
window.onresize = function() {
|
window.onresize = function() {
|
||||||
|
|
@ -21,7 +21,7 @@ function reloadPage() {
|
||||||
function sessionInfo() {
|
function sessionInfo() {
|
||||||
|
|
||||||
const touch_screen = (('ontouchstart' in document.documentElement) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)) ? "1" : "0";
|
const touch_screen = (('ontouchstart' in document.documentElement) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)) ? "1" : "0";
|
||||||
let message = "startSession{touch=" + touch_screen
|
let message = "startSession{session=" + sessionID + ",touch=" + touch_screen
|
||||||
|
|
||||||
const style = window.getComputedStyle(document.body);
|
const style = window.getComputedStyle(document.body);
|
||||||
if (style) {
|
if (style) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package rui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -23,6 +24,7 @@ type Application interface {
|
||||||
Params() AppParams
|
Params() AppParams
|
||||||
|
|
||||||
removeSession(id int)
|
removeSession(id int)
|
||||||
|
getCreateContentFunc() func(Session) SessionContent
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppParams defines parameters of the app
|
// AppParams defines parameters of the app
|
||||||
|
|
@ -66,7 +68,7 @@ type AppParams struct {
|
||||||
GoogleFonts string
|
GoogleFonts string
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStartPage(buffer *strings.Builder, params AppParams) {
|
func getStartPage(buffer *strings.Builder, sessionID int, params AppParams) {
|
||||||
buffer.WriteString(`<head>
|
buffer.WriteString(`<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>`)
|
<title>`)
|
||||||
|
|
@ -104,6 +106,11 @@ func getStartPage(buffer *strings.Builder, params AppParams) {
|
||||||
buffer.WriteString(appStyles)
|
buffer.WriteString(appStyles)
|
||||||
buffer.WriteString(`</style>
|
buffer.WriteString(`</style>
|
||||||
<style id="ruiAnimations"></style>
|
<style id="ruiAnimations"></style>
|
||||||
|
<script>
|
||||||
|
const sessionID = `)
|
||||||
|
buffer.WriteString(strconv.Itoa(sessionID))
|
||||||
|
buffer.WriteString(`;
|
||||||
|
</script>
|
||||||
<script src="/script.js"></script>
|
<script src="/script.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body id="body" onkeydown="keyDownEvent(this, event)">
|
<body id="body" onkeydown="keyDownEvent(this, event)">
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ func (storage *clientStorageData) handleEvent(command string, data DataObject) {
|
||||||
}
|
}
|
||||||
delete(storage.getResult, request)
|
delete(storage.getResult, request)
|
||||||
|
|
||||||
text, ok := data.PropertyValue("error")
|
text, ok := data.PropertyValue("values")
|
||||||
if !ok {
|
if !ok {
|
||||||
ErrorLog("'values' property not found (command: storageValues)")
|
ErrorLog("'values' property not found (command: storageValues)")
|
||||||
return
|
return
|
||||||
|
|
|
||||||
10
session.go
10
session.go
|
|
@ -11,6 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type bridge interface {
|
type bridge interface {
|
||||||
|
writeScript(script string)
|
||||||
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
|
||||||
|
|
@ -175,6 +176,7 @@ type Session 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)
|
||||||
|
writeScript(script string)
|
||||||
startUpdateScript(htmlID string) bool
|
startUpdateScript(htmlID string) bool
|
||||||
finishUpdateScript(htmlID string)
|
finishUpdateScript(htmlID string)
|
||||||
sendResponse()
|
sendResponse()
|
||||||
|
|
@ -508,6 +510,14 @@ func (session *sessionData) removeProperty(htmlID, property string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (session *sessionData) writeScript(script string) {
|
||||||
|
if session.bridge != nil {
|
||||||
|
session.bridge.writeScript(script)
|
||||||
|
} else {
|
||||||
|
ErrorLog("No connection")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (session *sessionData) startUpdateScript(htmlID string) bool {
|
func (session *sessionData) startUpdateScript(htmlID string) bool {
|
||||||
if session.bridge != nil {
|
if session.bridge != nil {
|
||||||
return session.bridge.startUpdateScript(htmlID)
|
return session.bridge.startUpdateScript(htmlID)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,16 @@ func createWasmBridge(close chan DataObject) bridge {
|
||||||
return bridge
|
return bridge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bridge *wasmBridge) writeScript(script string) {
|
||||||
|
if ProtocolInDebugLog {
|
||||||
|
DebugLog("Run script:")
|
||||||
|
DebugLog(script)
|
||||||
|
}
|
||||||
|
|
||||||
|
window := js.Global().Get("window")
|
||||||
|
window.Call("execScript", script)
|
||||||
|
}
|
||||||
|
|
||||||
func (bridge *wasmBridge) startUpdateScript(htmlID string) bool {
|
func (bridge *wasmBridge) startUpdateScript(htmlID string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,10 @@ func (bridge *webBridge) initBridge() {
|
||||||
bridge.updateScripts = map[string]*strings.Builder{}
|
bridge.updateScripts = map[string]*strings.Builder{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bridge *webBridge) writeScript(script string) {
|
||||||
|
bridge.writeMessage(script)
|
||||||
|
}
|
||||||
|
|
||||||
func (bridge *webBridge) startUpdateScript(htmlID string) bool {
|
func (bridge *webBridge) startUpdateScript(htmlID string) bool {
|
||||||
if _, ok := bridge.updateScripts[htmlID]; ok {
|
if _, ok := bridge.updateScripts[htmlID]; ok {
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue