win_main.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // package win_main -- главное окно приложения
  2. package win_main
  3. import (
  4. _ "embed"
  5. "fmt"
  6. "log"
  7. "net/url"
  8. "runtime"
  9. "sync"
  10. "time"
  11. "github.com/zserge/lorca"
  12. // "wartank/desktop/win_users"
  13. "wartank/pkg/components/safebool"
  14. "wartank/pkg/types"
  15. )
  16. const (
  17. strWinMainName = "win_main" // Контрольная строка для сторожа потоков
  18. )
  19. //go:embed win_main.html
  20. var strWinHtml string
  21. // WinMain -- главное окно приложения
  22. type WinMain struct {
  23. desktop types.IDesktop
  24. store types.IStore
  25. win lorca.UI
  26. block sync.Mutex
  27. isWork *safebool.SafeBool
  28. ws types.IWebSocket
  29. }
  30. // NewWinMain -- возвращает новое окно десктопа
  31. func NewWinMain(desktop types.IDesktop) (*WinMain, error) {
  32. if desktop == nil {
  33. return nil, fmt.Errorf("NewWinMain(): IDesktop == nil")
  34. }
  35. sf := &WinMain{
  36. desktop: desktop,
  37. store: desktop.Store(),
  38. isWork: safebool.NewSafeBool(),
  39. ws: desktop.Ws(),
  40. }
  41. args := []string{}
  42. if runtime.GOOS == "linux" {
  43. args = append(args, "--class=Lorca")
  44. }
  45. var err error
  46. sf.win, err = lorca.New("data:text/html,"+url.PathEscape(strWinHtml), "", 640, 480, args...)
  47. if err != nil {
  48. return nil, fmt.Errorf("NewWinMain(): in create win, err=\n\t%w", err)
  49. }
  50. go sf.close()
  51. return sf, nil
  52. }
  53. // Работает в отдельном потоке, главный цикл окна
  54. func (sf *WinMain) Run() {
  55. log.Println("WinMain.Run()")
  56. sf.win.Bind("close_win", sf.onClose)
  57. sf.win.Bind("bot_list", sf.onUsers)
  58. go sf.timeServer()
  59. <-sf.win.Done() // Ожидание закрытия окна
  60. sf.desktop.CancelApp()
  61. }
  62. // Открывает окно с пользователями
  63. func (sf *WinMain) onUsers() {
  64. log.Println("WinMain.onUsers()")
  65. go sf.desktop.DictBot().Show()
  66. }
  67. // Проверяет наличие работающего сервера, работает в отдельном потоке
  68. func (sf *WinMain) timeServer() {
  69. for {
  70. time.Sleep(time.Second * 2)
  71. timeBeg := time.Now().UTC().UnixMicro()
  72. dictResp, err := sf.ws.Read("/server/time")
  73. if err != nil {
  74. log.Printf("WinMain.timeServer(): in send request to server, err=\n\t%v\n", err)
  75. sf.desktop.CancelApp()
  76. return
  77. }
  78. timeEnd := time.Now().UTC().UnixMicro() - timeBeg
  79. strErr := dictResp["err"]
  80. if strErr != "" {
  81. js := fmt.Sprintf(`
  82. function SetTimeServer(){
  83. var _el = document.getById("/server/time");
  84. _el.innerText=%q;
  85. }
  86. SetTimeServer()
  87. `, err)
  88. sf.win.Eval(js)
  89. continue
  90. }
  91. strTime := dictResp["/server/time"]
  92. js := fmt.Sprintf(`
  93. function SetTimeServer(){
  94. var _el = document.getElementById("/server/time");
  95. _el.innerText=%q;
  96. }
  97. SetTimeServer()
  98. `, strTime)
  99. sf.win.Eval(js)
  100. js = fmt.Sprintf(`
  101. function SetPingServer(){
  102. var _el = document.getElementById("/server/ping");
  103. _el.innerText="%v мкСек";
  104. }
  105. SetPingServer()
  106. `, timeEnd)
  107. sf.win.Eval(js)
  108. }
  109. }
  110. // Закрывает приложение
  111. func (sf *WinMain) onClose() {
  112. log.Println("WinMain.onClose()")
  113. sf.win.Close()
  114. }
  115. // close -- ожидает отмены глобального контекста
  116. func (sf *WinMain) close() {
  117. <-sf.desktop.CtxApp().Done()
  118. log.Println("WinMain.close()")
  119. sf.block.Lock()
  120. defer sf.block.Unlock()
  121. if !sf.isWork.Get() {
  122. return
  123. }
  124. sf.isWork.Reset()
  125. sf.win.Close()
  126. sf.desktop.Wg().Done(strWinMainName)
  127. }