Гость
Форумы / Caché, Ensemble, DeepSee, MiniM, IRIS, GT.M [игнор отключен] [закрыт для гостей] / Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута") / 12 сообщений из 12, страница 1 из 1
05.12.2017, 17:22
    #39564581
MyasnikovIA
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута")
Доброго времени суток.

Решил поделиться с коллегами наболевшим. Долгое время раздражала отсутствие интерактивности при работе в Cache' через вэб технологию. Что это значит:
Допустим нам надо выполнить очень большой SQL запрос, поместить результат в EXEL (xml) файл. , и по окончанию закачать его на сторону клиента, причем самое гадкое в том, что клиент очень желает видеть процесс создания этого файла. А еще веселье в том, что у клиента очень шаловливые ручки, и он любит обновлять страницу, а то и вовсе закроет браузер. При повторной загрузке он конечно же опять нажмет на кнопку старта, и все начнется снова в новом процессе. Мне кажется данная проблема знакома многим.

Стандартный вызов #server(..Test(Arg1,arg2))# тут явно не поможет.

Для решения таких задач разработал класс HTML.RunJob https://github.com/MyasnikovIA/HTML.RunJob

Опять же приветствуется конструктивная критика, что можно улучшить. Буду очень признателен.

Пример применения (есть на ginhab):
Код: html
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
Class User.TestRunJob Extends %CSP.Page
{

ClassMethod OnPage() As %Status
{
     ;  <script language="JavaScript" type="text/javascript" src="HTML.RunJob.cls"></script>
     ;  <script language="JavaScript" type="text/javascript" src="%25ZHTML.RunJob.cls"></script> 
      
    &html< 
      <script language="JavaScript" type="text/javascript" src="%25ZHTML.RunJob.cls"></script>
      <button onclick='runProcess()'>Запустить процесс</button>
      <button onclick='KillProcess()'>Уничтожить процесс</button>
      <br>
      <br>
      <br>Уничтожить процесс: <button onclick='alert(callJob("..KillProc2",this.innerHTML))' id='KillProc'>---</button>
      <br>
      <br>
      <div id='info'>FrmCache</div>
      <br><progress id='progress' value="0" max="100" style='width:100%'></progress>
      <br>
      <div id='FrmCache'>FrmCache</div>
      <br>
      <br>
      <div id='demo'>eee</div>
      <br>
      <script type="text/javascript" >
      
      // Синхронный запуск класс метода
      // alert(callJob("..Test2"));

      // Синхронный запуск класс метода(Полный путь к классметоду)
      alert(callJob("User.TestRunJob.Test2"));
     
      /// функция срабатывает перед вызовом класс метода
      beginFun=function(){
          
      } 
      
      /// функция обработки запроса состояния работы процесса
      ProgressFun=function(arg){
         document.getElementById("demo").innerHTML='Wor progress:'+JSON.stringify(arg);
         if (arg.js!=undefined){  eval(arg.js);    }
         if (arg.UserJob!=undefined){  document.getElementById("KillProc").innerHTML = arg.UserJob;    }
      }
     
      /// функция срабатывает по окончанию работы процесса
      CalBackFun=function(arg){
          // document.getElementById("FrmCache").innerHTML =JSON.stringify(arg);
          document.getElementById("demo").innerHTML='';
          if (''+arg=={}){     alert('Работа закончена')    }
          document.getElementById("progress").value=0;
      }
     
      
      var JobID="MYJoB_3";
      
      /// Параметры обработки запроса
      var param=[beginFun,ProgressFun,CalBackFun,JobID,1000];
      /// запуск процесса повторно после перезагрузки страницы
      refJob(param);
      
      runProcess=function(){
         var res=callJob("..Test",param);
         document.getElementById("demo").innerHTML=res;
      }
      
      KillProcess=function(){
          killJob(JobID) ;
      }
      
     </script>
    >
    w ##class(%SYS.System).InstanceGUID()
    Quit $$$OK
}

ClassMethod KillProc2(JobProc)
{
    w $zu(4,JobProc)
}

ClassMethod Test2()
{
    w $ZDT($h)
}

///Процесс который будет работать  параллельно и очень долго  
ClassMethod Test()
{
    
    ; %runjob - имя глобала , через который происходит обмен Web морды и Cache` процесса
    s count=1000
    for a=1:1:count {   
       h 1
       s @%runjob@("info")= " Счетчик внутри процесса "_a
       s val=100\count*a
       s jsCode=""
       s jsCode=jsCode_" document.getElementById(""progress"").max = "_count_"; "
       s jsCode=jsCode_" document.getElementById(""progress"").value = "_a_"; "
       s jsCode=jsCode_" document.getElementById(""FrmCache"").innerHTML ="""_$ZDT($h)_" - "_a_"  "_val_"%"" "
       ; s @%runjob@("eval")=jsCode
       s @%runjob@("js")=jsCode
       s @%runjob@("UserJob")=$JOB
    }
    w $zdt($h)
    s @%runjob@("OK")=1 ; сообщаем Web морде о том, что процесс закончен корректно
    q
}

}
...
Рейтинг: 0 / 0
06.12.2017, 00:56
    #39564761
Блок А.Н.
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута")
MyasnikovIA,

Что-то все-таки это слишком большой огород для такой задачи.
Мне кажется, тут все и стандартными средствами делается несложно, но при использовании стандартных средств как-то больше уверенности.

Из своих подобных изобретений могу назвать многоуровневые статусы задач. Т.е. процесс может устанавливать статус не всей задачи целиком, а только одного определенного уровня. При установке определенного уровня статуса вышестоящие не затрагиваются, а нижестоящие затираются. Показалось очень удобным, применял в своей библиотеке формирования *.ODS файлов.
...
Рейтинг: 0 / 0
06.12.2017, 04:20
    #39564798
MyasnikovIA
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута")
Блок А.Н.,

Из сообщения я понял, что есть способ проще и легче. Только не понял какой. Можно пример, или ссылку где можно изучить эту технологию :)
А огород написан по той причине, что не знал иного способа. Хотел бы прокачать свой уровень, за счет коллег :)
...
Рейтинг: 0 / 0
06.12.2017, 09:03
    #39564829
krvsa
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута")
MyasnikovIA , помимо кащейских
Код: javascript
1.
2.
3.
#server(..Test(Arg1,arg2))#
// и
#call(..Test(Arg1,arg2))#


Есть и "стандартные" методы общения клиента с сервером... Например все тот же ajax/.

Против повторных запусков используется простая блокировка "сигнальных" узлов/глобалов...

Остается организовать прогресс на сервере и отображение его на клиенте.
...
Рейтинг: 0 / 0
06.12.2017, 10:57
    #39564890
Блок А.Н.
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута")
MyasnikovIA,

Ну, собственно, krvsa все сказал, только я бы на #call не особо надеяться, как способ асинхронного вызова.
Не возражаете, если на псевдокоде?

Веб страница:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
<Кнопка запуска>
<Область отображения прогресса>
...
</Область отображения прогресса>
<script language=javascript>
ЗапуститьОтчет(){...}
ПроверитьСостояниеПрогресса(){...}
ПроверитьРазрешениеЗапускаСВыбраннымиПараметрами(){...}
</script>

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
/// Класс отчета. Большинства методов можно выносить в абстрактный родительский класс
Class Report
{
/// Запустить отчет асинхронно. Вернет 1, если запущено
ClassMethhod RunAsync(params) as %Boolean
{
 ret:'..CheckStartPermission(params) 0
 job PrepareData(params)
 ret 1
}
/// Проверить разрешение старта с выбранными параметрами
Classmethod CheckStartPermission(params) as %Boolean
{
 s permisson=..Lock(params) 
 d ..Unlock(params)
 ret permission
}
ClassMethod Lock(params)
{
 lock ^report(params):0
 ret $test
}
ClassMethod Unlock(params)
{
 lock -^report(params)
}
ClassMethod PrepareData(params)
{
 s lock=..Lock(params)
 ret:'lock
 /// Установить статус процесса 

 for
 {
 ///Обновить статус процесса
 ....
 }
 d ..Unlock(params)
}
}

Все, в общем, просто, и все вы это знаете
...
Рейтинг: 0 / 0
06.12.2017, 11:22
    #39564911
MyasnikovIA
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута")
krvsa,

Как раз это и реализовано в HTML.RunJob
Запускается процесс, при этом инициируется глобал с именем идентификатора "MYJoB_3" и глобальна и переменная с именем %runjob
Все значения записанные в глобал @%runjob@(“Arg1”)=”Val” в процессе опроса состояния вернутся как JSON объект {…,”Arg1”:”Val”} и будут помещены в качестве входного аргумента JS функции “ ProgressFun=function(arg){ } “ – из примера

Таким образом организован обмен информацией из запущенного процесса и браузером.

Если глобал будет уничтожен, или в нем появится ветка с именем “OK”=1 , тогда опрос состояния процесса прекратится и запустится JS функция CalBackFun=function(arg){ }

Что касается огорода, то основной код был взят из JS “/csp/broker/cspxmlhttp.js“ ответная часть на сервере cache’ тоже взята из системного класса %CSP.Broker.cls . все было переработано и объединено в одном классе(для удобства развертывания).
...
Рейтинг: 0 / 0
06.12.2017, 11:49
    #39564932
krvsa
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута")
MyasnikovIAКак раз это и реализовано в HTML.RunJob
Дело твое...
Просто я согласен с этим высказыванием
Блок А.Н.Что-то все-таки это слишком большой огород для такой задачи.
...
Рейтинг: 0 / 0
06.12.2017, 11:54
    #39564938
MyasnikovIA
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута")
В JS появляются следующие функции :
callJob – функция запуска процесса
refJob - функция восстановления процесса
killJob - функция уничтожения процесса
и если библиотека подключается в cache классе, то библиотека cspbroker.js не будет подключена, в связи с чем я переопределяю js функцию cspCallHttpServerMethod
она вызывается в тех случаях когда в JS коде встречается конструкция #call( … )#

При запуске callJob в первом параметре передается имя классметода в полном или коротком представлении ( "..Test2" или "User.TestRunJob.Test2" )

Если вторым аргументом подается массив простой аргумент (строка , число) тогда работает как обыкновенный синхронный запрос, аналогично работе #server(…)#.

Если на вход вторым аргументом подается массив объектов в виде:
var param=[beginFun,ProgressFun,CalBackFun,”JobID”,1000];
Код: html
1.
2.
3.
4.
5.
 beginFun(){}         – js функция срабатывает сразу же после запуска cache метода
ProgressFun(arg){}  – js функция срабатывает при опросе состояния процесса  
CalBackFun(arg){}   – js  функция срабатывает после окончания работы cache  класс-метода, или если процесс уничтожен
”JobID”        –  идентификатор процесса по которому производится опрос состояния
1000            –   интервал опроса состояния процесса

тогда класс метод запускается в параллельном потоке. При этом функция ProgressFun повторно вызывается через 1000 мсек. (время задается в параметре четвертым аргументом) .

Все остальные аргументы помещаются как входящие аргументы cache класс-метода
...
Рейтинг: 0 / 0
06.12.2017, 11:55
    #39564939
MyasnikovIA
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута")
все это после подключения в HTML коде класса
<script language="JavaScript" type="text/javascript" src="HTML.RunJob.cls"></script>
...
Рейтинг: 0 / 0
06.12.2017, 11:56
    #39564940
MyasnikovIA
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута")
krvsa,

Спасибо за мнение. Это на самом деле важно.
...
Рейтинг: 0 / 0
06.12.2017, 19:18
    #39565375
Sheonn
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута")
MyasnikovIA,
Т.е. в CSP это использовать нельзя из-за переопределения cspCallHttpServerMethod?
...
Рейтинг: 0 / 0
07.12.2017, 04:51
    #39565502
MyasnikovIA
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута")
Sheonn,

Использовать можно
в классе HTML.RunJob присутствует следующая конструкция (в районе строки 592 -+ 5 строк)
Код: javascript
1.
2.
3.
     if (typeof cspCallHttpServerMethod !== 'function') {
         cspCallHttpServerMethod=callJob;
     }



Благодаря этой конструкции, если функция cspCallHttpServerMethod не определена, тогда она определяется.

Если определить в CSP внутри тэга HEAD
Код: html
1.
2.
3.
<HEAD> 
   <script language="JavaScript" type="text/javascript" src="HTML.RunJob.cls"></script>
</HEAD> 


Перед выполнением Cache добавит пере закрывающим тэгом "</HEAD>" библиотеки "cspxmlhttp.js" и "cspbroker.js"
и получится конструкция
Код: html
1.
2.
3.
<HEAD> 
<script language="JavaScript" type="text/javascript" src="HTML.RunJob.cls"></script>
<script language="JavaScript" type="text/javascript" src="/csp/broker/cspxmlhttp.js"></script><script language="JavaScript" type="text/javascript" src="/csp/broker/cspbroker.js"></script></HEAD>




В связи с этим cspCallHttpServerMetho будет сначала создан в HTML.RunJob.cls а затем переопределен в cspxmlhttp.js
и все будет работать по старому.

Код: html
1.
2.
3.
callJob – функция запуска процесса
refJob - функция восстановления процесса
killJob - функция уничтожения процесса


Никто не запрещает закомментировать HTML.RunJob условие перед инициализацией , и оставить
Код: javascript
1.
cspCallHttpServerMethod=callJob;


Но надо помнить, что подключать HTML.RunJob надо будет после закрывающего тэга </head> иначе библиотека "cspxmlhttp.js" опять переопределит её.

Это может понадобится, в тех случаях, когда есть желание использовать HTML.RunJob и есть необходимость скрыть от пользователя имя вызываемого класс метода при применении конструкции:
Код: html
1.
 #call(..Test([beginFun,ProgressFun,CalBackFun,”JobID”,1000],arg1,arg2) )#
...
Рейтинг: 0 / 0
Форумы / Caché, Ensemble, DeepSee, MiniM, IRIS, GT.M [игнор отключен] [закрыт для гостей] / Интерактивный вызов класс-методов Cache из Вэббраузера (без "Таймаута") / 12 сообщений из 12, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]