вторник, 2 июля 2024 г.

Customize Citrix StoreFront

Общий смысл работы кастомизации:
Во время инициализации отображения элементов на UI сделать запрос в базу данных на предмет наличия у текущего StoreApp(это может быть и приложение и десктоп) активных сессий и показать это пользователю.

 

 Использовал эти источники:
    https://developer-docs.citrix.com/en-us/storefront/storefront-client-ui-customization-api/api-reference.html
    https://www.simonscitrix.com/2018/01/customizing-storefront-with-awl-citrix.html?m=1
    https://www.citrixguru.com/2016/03/08/lab-ultimate-storefront-customization-guide/
    https://www.carlstalhood.com/storefront-cr-tweaks/#customize3

Как это работает:
В FtoreFront заложен механизм катомизации UI, позволяющий перехватывать некоторые события и производить изменения.
Для перехвата используется скрипт
«C:\inetpub\wwwroot\Citrix\StoreWeb\custom\script.js».
Он позволяет также отправить ajax запрос на сервер и изменить UI. В качестве сервера я использовал IIS+PHP.

Запрос: script.js

//Detail Info customization
CTXS.Extensions.beforeShowAppInfo = function(app) {
    var ihElement = document.querySelector('section.appInfoView.scrollable div.appInfoHeader div.appInfoHeaderDetails');
    if (ihElement) {
        var custP = ihElement.querySelectorAll('p');
        if (custP) {
            for ( item of custP) {
                item.remove();
            }
        }
    }
    CTXS.ExtensionAPI.proxyRequest({
        type: "POST",
        url: "/PHP/get.php",
        timeout: 1000,
        data: { msg: app.desktophostname },
        success: function(msg){
            if (msg != '') {
                customize(0, msg, null);
            }
        }
    });
};
 
//App Tile customization
CTXS.Extensions.getAppTileMarkup = function (app, appDisplayName, defaultMarkupFn) {
    //console.log(app);
    CTXS.ExtensionAPI.proxyRequest({
        type: "POST",
        url: "/PHP/get.php",
        timeout: 1000,
        data: { msg: app.desktophostname },
        success: function(msg){
            if (msg != '') {
                customize(0, msg, app.shortid);
            }
        }
    });
    return defaultMarkupFn();
}
 
 
function customize(num, msg, appShortid) {    
    var appElement, stl;        
    if (appShortid != null) {
        stl = ' style="margin-top: -36px" ';
        var appElement = document.querySelector('[data-shortid="' + appShortid + '"]');
    } else {
        stl = ' style="margin: 12px 0px" ';
        var appElement = document.querySelector('section.appInfoView.scrollable div.appInfoHeader div.appInfoHeaderDetails');
    }
    if (appElement) {
        var AppStatus = msg.split(';');
        var ins = '';
        if (AppStatus[2] == 1) { //InMaintenanceMode
            ins = '<p class="storeapp-name" style="margin-top: -30px; color: red">Режим обслуживания</p>'
        } else {
            if (AppStatus[3] > 0) {  //_SessionCount
                if (AppStatus[5] >= 2) {  //SessionState
                    var d1 = Date.parse(AppStatus[4])  //LogOnTime
                    var now = new Date();
                    var diff = Math.round((Math.abs(now.getTime() - d1) / 3600000) - 4);
                        ins = '<p class="storeapp-name" '+stl+'><span style="color: green">Сессия:</span> '+AppStatus[6]+' '+diff+' ч.<br>'+(AppStatus[5]==2 ? '<span style="color: green">Connected</span>' : '<span style="color: gray">Disconnected</span>')+'</p>' 
                } else {
                    ins = '<p class="storeapp-name" '+stl+'>Подключение...</p>' 
                }
            }        
        }
        //инъекция HTML кода  
        appElement.insertAdjacentHTML('beforeend', ins);
    } else {
        if (num < 20)  {
            setTimeout(function() { customize(num+1, appShortid, msg); }, 100);
        }
    }
}


Сервер: 

Настроил в IIS поддержку PHP пошаговый разбор есть здесь
https://www.dmosk.ru/instruktions.php?object=iis-php
Скачал драйвер MS SQL для PHP
https://learn.microsoft.com/en-us/sql/connect/php/download-drivers-php-sql-server?view=sql-server-ver16
Подключил его в php.ini

extension=C:\php-8.3.6-Win32-vs16-x64\ext\php_sqlsrv_83_ts_x64.dll

Установил ODBC драйвер (18 версии, более младшие выдавали ошибку)
https://learn.microsoft.com/en-us/sql/connect/odbc/download-odbc-driver-for-sql-server?view=sql-server-ver16

В базе данных создал учетку CTX_get для доступа к базе на чтение.
В UserMappings указал маппинг на БД сайта Citrix_site_database и указал роли db_datareader + chrBroker(потребовалось для выполнения процедуры запроса chb_State.PickMainVDISession)

За основу своего запроса взял запрос, который использует Citrix при выполнении powerShell команды Get-BrokerMachine. Там огромный тяжелый запрос, я оставил в нем только то что мне надо было.

get.php

<?php

$conn = sqlsrv_connect('<SQL server name>\SQLEXPRESS,1433', array('Database'=>"Citrix_site_database", 'UID'=>'CTX_get', 'PWD'=>'PASSWORD', 'Encrypt'=>'False'));

$req = "select 
  CW.Uid as _Uid, 
  WD.HostedMachineName, 
  CW.InMaintenanceMode, 
  (
    W.CurrentSessions + W.PendingSessions
  ) as _SessionCount, 
  S.LogOnTime, 
  S.SessionState, 
  TUN.SAMName as _SessionUserName
from 
  chb_Config.Workers CW 
  inner join chb_State.Workers W on CW.Uid = W.Uid 
  inner join chb_State.WorkerDiags WD on CW.Uid = WD.Uid 
  left outer join chb_State.Sessions S on (
    (W.SessionSupport = 0) and (S.WorkerUid = W.Uid) 
    and (
      S.Uid = case when (W.CurrentSessions <= 0) 
      or (W.SessionSupport <> 0) then null when (W.CurrentSessions = 1) then S.Uid else chb_State.PickMainVDISession(W.Uid) end
    )
  ) 
  left outer join chb_State.AccountNames TUN on S.TrustedUserUid = TUN.Uid 
where 
  WD.HostedMachineName = '".$_POST['msg']."';"; //условие по имени машины
  
$res = sqlsrv_query($conn, $req);

if ($res) {
  $rows = sqlsrv_has_rows( $res );
  if ($rows === true) {
    $row = sqlsrv_fetch_array( $res, SQLSRV_FETCH_ASSOC);
    $ret = '';
    foreach ($row as $item) {
      if (is_a($item, 'DateTime')) {
        $ret .= $item->format('Y-m-d H:i:s') . ';';
      } else {        
        $ret .= $item.';';
      }
    }
    echo $ret;
  }
}

sqlsrv_free_stmt( $res);

?>

Комментариев нет:

Отправить комментарий