File size: 4,696 Bytes
bbfde3f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Session-based file storage with automatic cleanup
const fs = require('fs').promises;
const path = require('path');

class SessionManager {
  constructor() {
    this.sessions = new Map();
    this.cleanupInterval = 30 * 60 * 1000; // 30 minutes
    this.sessionTimeout = 60 * 60 * 1000; // 1 hour
    
    // Start cleanup timer
    setInterval(() => this.cleanupExpiredSessions(), this.cleanupInterval);
  }

  // Create a new session
  createSession() {
    const sessionId = Date.now() + '-' + Math.random().toString(36).substr(2, 9);
    const sessionDir = `temp-sessions/${sessionId}`;
    
    const session = {
      sessionId,
      createdAt: Date.now(),
      lastActivity: Date.now(),
      directory: sessionDir,
      files: [],
      batches: [],
      reports: []
    };
    
    this.sessions.set(sessionId, session);
    
    // Create session directory
    this.ensureSessionDirectory(sessionDir);
    
    return session;
  }

  // Get existing session or create new one
  getOrCreateSession(sessionId) {
    if (sessionId && this.sessions.has(sessionId)) {
      const session = this.sessions.get(sessionId);
      session.lastActivity = Date.now();
      return session;
    }
    return this.createSession();
  }

  // Update session activity (keeps it alive)
  heartbeat(sessionId) {
    if (this.sessions.has(sessionId)) {
      const session = this.sessions.get(sessionId);
      session.lastActivity = Date.now();
      return true;
    }
    return false;
  }

  // Add file to session
  addFileToSession(sessionId, fileInfo) {
    const session = this.sessions.get(sessionId);
    if (session) {
      session.files.push(fileInfo);
      session.lastActivity = Date.now();
    }
  }

  // Add batch to session
  addBatchToSession(sessionId, batchInfo) {
    const session = this.sessions.get(sessionId);
    if (session) {
      session.batches.push(batchInfo);
      session.lastActivity = Date.now();
    }
  }

  // Get session files
  getSessionFiles(sessionId) {
    const session = this.sessions.get(sessionId);
    return session ? session.files : [];
  }

  // Get session batches
  getSessionBatches(sessionId) {
    const session = this.sessions.get(sessionId);
    return session ? session.batches : [];
  }

  // Clean up expired sessions
  async cleanupExpiredSessions() {
    const now = Date.now();
    const expiredSessions = [];

    for (const [sessionId, session] of this.sessions) {
      if (now - session.lastActivity > this.sessionTimeout) {
        expiredSessions.push(sessionId);
      }
    }

    for (const sessionId of expiredSessions) {
      await this.destroySession(sessionId);
    }

    if (expiredSessions.length > 0) {
      console.log(`🧹 Cleaned up ${expiredSessions.length} expired sessions`);
    }
  }

  // Manually destroy a session
  async destroySession(sessionId) {
    const session = this.sessions.get(sessionId);
    if (!session) return;

    try {
      // Delete all session files
      await this.deleteDirectory(session.directory);
      console.log(`🗑️ Deleted session directory: ${session.directory}`);
    } catch (error) {
      console.warn(`Failed to delete session directory ${session.directory}:`, error.message);
    }

    // Remove from memory
    this.sessions.delete(sessionId);
  }

  // Ensure session directory exists
  async ensureSessionDirectory(sessionDir) {
    try {
      await fs.mkdir(sessionDir, { recursive: true });
    } catch (error) {
      if (error.code !== 'EEXIST') {
        throw error;
      }
    }
  }

  // Recursively delete directory
  async deleteDirectory(dirPath) {
    try {
      const stats = await fs.stat(dirPath);
      if (stats.isDirectory()) {
        const files = await fs.readdir(dirPath);
        await Promise.all(
          files.map(file => this.deleteDirectory(path.join(dirPath, file)))
        );
        await fs.rmdir(dirPath);
      } else {
        await fs.unlink(dirPath);
      }
    } catch (error) {
      if (error.code !== 'ENOENT') {
        throw error;
      }
    }
  }

  // Get session stats
  getSessionStats() {
    return {
      activeSessions: this.sessions.size,
      sessions: Array.from(this.sessions.values()).map(s => ({
        sessionId: s.sessionId,
        createdAt: s.createdAt,
        lastActivity: s.lastActivity,
        filesCount: s.files.length,
        batchesCount: s.batches.length
      }))
    };
  }
}

// Global session manager instance
const sessionManager = new SessionManager();

module.exports = sessionManager;