Если возникла ситуация, что произошел несанкционированный сбой в сети и после перезагрузки остается на висеть сеанс (хотя на самом деле пользователь
не подключен и сеанс неактивен), то появится диалоговое окно с запросом отключить или нет предыдущий сеанс.
не подключен и сеанс неактивен), то появится диалоговое окно с запросом отключить или нет предыдущий сеанс.
//!!! Для обычного приложения версии 8.2
//Размещать код следует в начало Процедуры ПриНачалеРаботыСистемы модуля обычного приложения.
//Принцип работы - Если возникла ситуация, что произошел несанкционированный сбой в сети и после перезагрузки остается на //сервере висеть сеанс (хотя на самом деле пользователь
//не подключен и сеанс неактивен), то появится диалоговое окно с запросом отключить или нет предыдущий сеанс.
//ПО ПРОСЬБЕ вставлю фрагмент, кот-ый автоматически определит Имя БД, ИмяСервера
//**********
СтрокаСоединения = СтрокаСоединенияИнформационнойБазы();
Если СтрЧислоВхождений(ВРег(СтрокаСоединения), "FILE=") Тогда
Возврат;
КонецЕсли;
СтрДлина = СтрДлина(СтрокаСоединения);
// Ищем имя сервера
СтрокаСервера = ВыделитьПодстрокуСтрокиЗапуска(СтрокаСоединения, "Srvr=");
ИмяБД = ВыделитьПодстрокуСтрокиЗапуска(СтрокаСоединения, "Ref=");
// Если в имени сервера присутствует имя порта, то выделяем его
РазделительПорта = Найти(СтрокаСервера, ":");
Если РазделительПорта > 0 Тогда
ИмяСервера = Сред(СтрокаСервера, 1, (РазделительПорта - 1));
НомерПортаКластера = Сред(СтрокаСервера, (РазделительПорта + 1));
Иначе
ИмяСервера = СтрокаСервера;
ком = Новый COMОбъект("v81.COMConnector");
НомерПортаКластера = ком.RMngrPortDefault;
КонецЕсли;
//*******
ПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь();
ПризнакСеанса = 0;
//для обеспечения невозможности повторного входа пользователя, который уже присутствует в БД
//что делается:
ТекущийНомерСоединения=НомерСоединенияИнформационнойБазы();
УникальныйИдентификаторПользователя=ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;
ТекущееСоединениеИмяКомпьютера = ИмяКомпьютера();
ServerName = ИмяСервера; //Имя Вашего сервера 1С
connector = новый comОбъект("V82.COMConnector");
AgentConnection = Connector.ConnectAgent(ServerName);
МассивКластеров = AgentConnection.GetClusters();
//определяем кластёр как описание типов
Для каждого Кластер ИЗ МассивКластеров Цикл
Если (Кластер.HostName = ИмяСервера) и (Кластер.SyncPort=НомерПортаКластера) тогда КластерТекущейБД = Кластер;
//Думаю, что имя сервера будет совпадать с именем компа :)
// Сообщить(Кластер.HostName);
КонецЕсли;
Прервать;
КонецЦикла;
//Доступ на просмотр сеансов
AgentConnection.Authenticate(КластерТекущейБД,"Администратор","Пароль");
//Для получения ВСЕХ тек.сеансов для данной БД - для инфо.. потом закомм и заодно БД как описание типов
МассивСеансов = AgentConnection.GetSessions(КластерТекущейБД);
Для каждого Сеанс ИЗ МассивСеансов Цикл
Если (Сеанс.Infobase.Name = ИмяБД) и (Сеанс.UserName = ПользователиИнформационнойБазы.ТекущийПользователь().Имя) тогда
ОписаниеБД = Сеанс.Infobase;
КонецЕсли;
КонецЦикла;
// Для случаев с висящими сеансами
МассивВсехСессийБД = AgentConnection.GetInfoBaseSessions(КластерТекущейБД,ОписаниеБД);
Для каждого СессияБД ИЗ МассивВсехСессийБД Цикл
Если //(СессияБД.Host = ТекущееСоединениеИмяКомпьютера) И //ЭТО ЕСЛИ НАДО ИНИЦИАЛИЗАЦИЯ ПО КОМПУ
(СессияБД.UserName = ПользователиИнформационнойБазы.ТекущийПользователь().Имя) И
(СессияБД.Connection.Application = "1CV8")
тогда
Если СессияБД.Connection.ConnID <> ТекущийНомерСоединения
тогда
Режим = РежимДиалогаВопрос.ДаНет;
Текст = "Сеанс данного пользователя активен! " + СессияБД.UserName +
"| Закрыть предыдущий сеанс? При сбое в сети нажмите <<Да>>";
Ответ = Вопрос(Текст,Режим,0);
Если Ответ = КодВозвратаДиалога.Да тогда
AgentConnection.TerminateSession(КластерТекущейБД,СессияБД);
КонецЕсли;
Если Ответ = КодВозвратаДиалога.Нет тогда
ПризнакСеанса = 1;
Предупреждение("Внимание! Активно несколько сеансов для одного пользователя");
КонецЕсли;
КонецЕсли;
//если просто висяк,тада безоговорочно закроет на серваке висячий сеанс. проверить
Сообщить("НомерСоединения: " + СессияБД.Connection.ConnID + " Номер сеанса: " + СессияБД.SessionID);//Сеансы
КонецЕсли;
КонецЦикла;
//а если с другого компа под этим ползуном, ЗАКРЫВАТЬ БУДЕТ ГОСТЯ
//Этот фрагмент кода можно не включать, если Вам нужно просто закрыть висящий сеанс.
МассивСоединений=ПолучитьСоединенияИнформационнойБазы();
Для Каждого ТекСоединение Из МассивСоединений Цикл
Сообщить(ТекСоединение.НомерСоединения);
Если (ТекСоединение.ИмяПриложения="1CV8")
и(НЕ ТекСоединение.НомерСоединения=ТекущийНомерСоединения)
и(НЕ ТекСоединение.Пользователь=неопределено)
и(ТекСоединение.Пользователь.УникальныйИдентификатор=УникальныйИдентификаторПользователя)
и(ПризнакСеанса = 0)
//и(НЕ СессияБД.Host = ТекущееСоединениеИмяКомпьютера)
//и(ТекСоединение.Пользователь.ИмяКомпьютера = ТекущееСоединениеИмяКомпьютера)
тогда
Предупреждение("Пользователь с таким именем уже выполнил вход ! Имя ПК >> " + СессияБД.Host);
ЗавершитьРаботуСистемы(Ложь);
КонецЕсли;
КонецЦикла;
По просьбе — И еще добавить в Модуль новую функцию
// Функция выделяет необходимые части из строки запуска
//
Функция ВыделитьПодстрокуСтрокиЗапуска(СтрокаЗапуска, КлючПодстроки) Экспорт
НомерПервогоСимвола = Найти(ВРег(СтрокаЗапуска), ВРег(КлючПодстроки)) + СтрДлина(КлючПодстроки);
Для Счетчик = НомерПервогоСимвола По СтрДлина(СтрокаЗапуска) Цикл
Если Сред(СтрокаЗапуска, Счетчик, 1) = ";" Тогда
НомерПоследнегоСимвола = Счетчик - 1;
Прервать;
КонецЕсли;
КонецЦикла;
// Получаем искомую подстроку
ИскомаяПодстрока = Сред(СтрокаЗапуска, НомерПервогоСимвола, (НомерПоследнегоСимвола - НомерПервогоСимвола + 1));
Если Сред(ИскомаяПодстрока, 1, 1) = """" Тогда
// Если подстрока в кавычках, то выделяем их
ИскомаяПодстрока = Сред(ИскомаяПодстрока, 2, (СтрДлина(ИскомаяПодстрока) - 2));
КонецЕсли;
Возврат ИскомаяПодстрока; КонецФункции // ВыделитьПодстроку()
отформатируйте текст статьи
А для 1с7.7 подойдет?
Получается код вырубает не именно зависший сеанс, а все другие сеансы текущего пользователя
Есть какая то возможность определить простой соединения? Как я видел в консоли — в зависшем соединении — однофигово дата последней активности довольно актуальная ( : Скажем пользователь подвис 1 час назад последняя активность соединения минуту назад
Пока только так и получается, что надо зайти еще раз пользователю, чтобы убить пред. сеанс. Вариант есть, если использовать Регламентное задание, которое бы через какой-либо интервал проверяло активность пользователей.
А как проверить активность пользователей, если в системе есть что-то связанное с обработкой ожидания. например напоминалка, соотщалка…
(1) вася, более-менее навел красоту 🙂
Спасибо, но еще неплохо бы добавить след код, ну прописать полученные данные где надо
Показать
(7) igo1, И вам спасибо, я добавил. Но, правда, хотел чтобы код менялся в одном месте. Ну и ладно… Я считаю, что обработка строки — это довольно-таки серьезная штука и полезная. А вообще, Может быть и так, что наш с Вами получившийся код можно оптимизировать. Но в этом виде, думаю, пока подойдет для нетиповых конфиг.
Супер! А нет ли возможности реализации подобного функционала без использования com-объекта, чтобы на linux-сервере использовать по регламентному заданию, например?
Хотя в толстом клиенте запущенном с винды это должно отрабатывать и так, надо попробовать.
JusteRU(9), к сожалению, только чуть менее 2х лет в 1С… Как регламентное задание можно сделать. Пробовал на 2003м серваке. Не подошло, потому-что в фоновом режиме иногда выскакивало не в тему сообщение о наличии пользователя в сети. Надо еще немножко переработать для «фона». А насчет Линукса — Ведь ком объект я вызываю чтобы использовать агент-коннектор. Как в обход коннектора все «прокрутить» будет время-разберусь. Счас работу ищу 🙁
(2) g26516, пиарнусь немного. Для 7.7 и для 8.x подойдет мое детище —http://infostart.ru/public/248792/ .
(11) MadDAD, возьмем на заметку 🙂
хаха. А через Delphi такоя имтерестно реализовано…