opennx/SessionList.cpp
2025-08-08 20:34:09 +02:00

312 lines
8.9 KiB
C++

// $Id: SessionList.cpp 687 2012-02-18 00:00:24Z felfert $
//
// Copyright (C) 2006 The OpenNX Team
// Author: Fritz Elfert
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Library General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#if defined(__GNUG__) && !defined(__APPLE__)
#pragma implementation "SessionList.h"
#endif
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "SessionList.h"
#include "MySession.h"
#include <wx/dir.h>
#include <wx/filename.h>
#include "trace.h"
ENABLE_TRACE;
DEFINE_LOCAL_EVENT_TYPE(wxEVT_SESSIONLIST_ACTION);
class SessionTraverser : public wxDirTraverser
{
public:
SessionTraverser(wxArrayString& dirs) : m_dirs(dirs) { }
virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename))
{
return wxDIR_CONTINUE;
}
virtual wxDirTraverseResult OnDir(const wxString& dirpath)
{
wxString name = wxFileName::FileName(dirpath).GetFullName();
m_dirs.Add(name);
return wxDIR_IGNORE;
}
private:
wxArrayString& m_dirs;
};
class RmRfTraverser : public wxDirTraverser
{
public:
RmRfTraverser() { }
~RmRfTraverser()
{
int n = m_aFiles.GetCount() - 1;
while (n >= 0) {
myLogTrace(MYTRACETAG, wxT("Removing file %s"), VMB(m_aFiles[n]));
::wxRemoveFile(m_aFiles[n--]);
}
n = m_aDirs.GetCount() - 1;
while (n >= 0) {
myLogTrace(MYTRACETAG, wxT("Removing dir %s"), VMB(m_aDirs[n]));
::wxRmdir(m_aDirs[n--]);
}
}
virtual wxDirTraverseResult OnFile(const wxString& filename)
{
myLogTrace(MYTRACETAG, wxT("going to delete file %s"), VMB(filename));
m_aFiles.Add(filename);
return wxDIR_CONTINUE;
}
virtual wxDirTraverseResult OnDir(const wxString& dirpath)
{
myLogTrace(MYTRACETAG, wxT("going to delete dir %s"), VMB(dirpath));
m_aDirs.Add(dirpath);
return wxDIR_CONTINUE;
}
private:
wxArrayString m_aDirs;
wxArrayString m_aFiles;
};
WX_DECLARE_STRING_HASH_MAP(MySession, SessionHash);
SessionList::SessionList(wxString dir, wxEvtHandler* h)
: wxThreadHelper()
, m_dirName(dir)
, m_pAdminHandler(h)
, m_dir(NULL)
, m_reValid(false)
{
m_sessions = new SessionHash();
m_re = new wxRegEx();
if (m_re->Compile(wxT("(([TF])-)?([SC])-(.*)-([[:digit:]]+)-([[:xdigit:]]{32})$"), wxRE_ADVANCED))
m_reValid = true;
if (m_reValid && (!m_dirName.IsEmpty())) {
CreateThread();
m_thread->Run();
}
}
SessionList::~SessionList()
{
m_thread->Delete();
while (m_thread->IsRunning())
wxThread::Sleep(100);
if (m_dir != NULL)
delete m_dir;
delete m_re;
m_sessions->clear();
delete m_sessions;
}
void SessionList::SetDir(wxString dir)
{
m_dirName = dir;
if (m_reValid && (!m_dirName.IsEmpty())) {
if (m_thread == NULL) {
CreateThread();
m_thread->Run();
} else {
m_csDir.Enter();
if (m_dir)
delete m_dir;
m_dir = NULL;
m_csDir.Leave();
}
}
}
void SessionList::ScanDir()
{
wxCriticalSectionLocker dlocker(m_csDir);
if (m_dir == NULL) {
if (m_dirName.IsEmpty())
return;
if (!wxDir::Exists(m_dirName)) {
m_dirName = wxEmptyString;
return;
}
m_dir = new wxDir(m_dirName);
}
// get the names of all session directories
wxArrayString sdirs;
SessionTraverser traverser(sdirs);
m_dir->Traverse(traverser);
size_t cnt = sdirs.GetCount();
size_t i;
// Format of session dir name:
//
// ([TF]-)?[SC]-(.*)-[:digit:]+-[:xdigit:]{32}
//
// 1. element is session status
// "T-" resp. "F-" stands for terminated or failed respectively.
// If it is missing, the session is undefined (probably running).
//
// 2. element is session type
// S- resp. C- stands for server resp. client session type
//
// 3. element is host name of the NX server
// 4. element is port name
// 5. element is an md5sum. (//FE: For what data?)
//
bool changed = false;
SessionHash::iterator it;
size_t oldcount = m_sessions->size();
for (it = m_sessions->begin(); it != m_sessions->end(); ++it)
it->second.bSetTouched(false);
for (i = 0; i < cnt; i++) {
wxString tmp = sdirs[i];
if (m_re->Matches(tmp)) {
wxString md5 = m_re->GetMatch(tmp, 6);
it = m_sessions->find(md5);
if (it == m_sessions->end()) {
// New session found
long port;
m_re->GetMatch(tmp,5).ToLong(&port);
myLogTrace(MYTRACETAG,
wxT("State='%s', Type='%s', Host='%s', Port=%d, MD5='%s'"),
VMB(m_re->GetMatch(tmp,2)),
VMB(m_re->GetMatch(tmp,3)),
VMB(m_re->GetMatch(tmp,4)),
(int)port, VMB(md5));
// Create new hash entry
MySession s(m_dirName + wxFileName::GetPathSeparator() + tmp,
m_re->GetMatch(tmp,2), m_re->GetMatch(tmp,3),
m_re->GetMatch(tmp,4), port, md5);
(*m_sessions)[md5] = s;
if (m_pAdminHandler) {
wxCommandEvent ev(wxEVT_SESSIONLIST_ACTION, wxID_ANY);
ev.SetInt(SessionAdded);
ev.SetClientData(&(m_sessions->find(md5)->second));
m_pAdminHandler->AddPendingEvent(ev);
changed = true;
}
} else {
// Existing session found, mark it
it->second.bSetTouched(true);
}
}
}
bool finished = false;
while (!finished) {
finished = true;
for (it = m_sessions->begin(); it != m_sessions->end(); ++it) {
if (it->second.bGetTouched()) {
MySession::tSessionStatus st = it->second.eGetSessionStatus();
it->second.CheckState();
if (it->second.eGetSessionStatus() != st) {
if (m_pAdminHandler) {
wxCommandEvent ev(wxEVT_SESSIONLIST_ACTION, wxID_ANY);
ev.SetInt(SessionChanged);
ev.SetClientData(&it->second);
m_pAdminHandler->AddPendingEvent(ev);
changed = true;
}
}
} else {
wxString md5 = it->second.sGetMd5();
myLogTrace(MYTRACETAG, wxT("Session '%s' disappeared"), VMB(md5));
finished = false;
if (m_pAdminHandler) {
wxCommandEvent ev(wxEVT_SESSIONLIST_ACTION, wxID_ANY);
ev.SetInt(SessionRemoved);
ev.SetClientData(&it->second);
m_pAdminHandler->AddPendingEvent(ev);
changed = true;
}
RemoveFromList(md5);
break;
}
}
}
if (changed && (m_pAdminHandler != NULL)) {
wxCommandEvent ev(wxEVT_SESSIONLIST_ACTION, wxID_ANY);
ev.SetInt(UpdateList);
m_pAdminHandler->AddPendingEvent(ev);
}
if (m_sessions->size() != oldcount)
myLogTrace(MYTRACETAG, wxT("SessionList: Now %d sessions"), (int)m_sessions->size());
}
void
SessionList::RemoveFromList(wxString md5)
{
m_sessions->erase(md5);
}
void
SessionList::CleanupDir(wxString &dir)
{
if (!dir.IsEmpty()) {
{
myLogTrace(MYTRACETAG, wxT("CleanupDir '%s'"), VMB(dir));
wxDir d(dir);
RmRfTraverser t;
d.Traverse(t);
}
::wxRmdir(dir);
}
}
wxThread::ExitCode
SessionList::Entry()
{
int cnt = 0;
while (!m_thread->TestDestroy()) {
if (cnt-- == 0) {
ScanDir();
cnt = 20;
}
wxThread::Sleep(100);
}
return 0;
}