1+ const EventEmitter = require ( 'events' ) ;
2+ const eventEmitter = new EventEmitter ( ) ;
3+ const fs = require ( 'fs' ) . promises ;
4+ const path = require ( 'path' ) ;
5+ const vm = require ( 'vm' ) ;
6+
7+ const scriptsDirectory = './scripts' ;
8+
9+ class CoCreateLazyLoader {
10+ constructor ( crud ) {
11+ this . wsManager = crud . wsManager
12+ this . crud = crud
13+ this . init ( )
14+ }
15+
16+ init ( ) {
17+ // TODO: check CoCreate.config.js using config
18+ const lazyLoadConfig = Config ( 'lazyload' )
19+ if ( ! lazyLoadConfig )
20+ return
21+
22+ for ( let key of Object . keys ( lazyLoadConfig . lazyload ) ) {
23+ let moduleConfig = lazyLoadConfig . lazyload [ key ] ;
24+ eventEmitter . on ( moduleConfig . event , async ( ) => {
25+ try {
26+ const module = await require ( moduleConfig . path ) ;
27+
28+ if ( typeof moduleConfig . unload === 'number' ) {
29+ setTimeout ( ( ) => {
30+ // Implement module unload logic
31+ } , moduleConfig . unload ) ;
32+ }
33+
34+ // Use openaiModule here
35+
36+ } catch ( error ) {
37+ console . log ( )
38+ }
39+ } ) ;
40+
41+ console . log ( "Module Key:" , key ) ;
42+ console . log ( "Module Config:" , moduleConfig ) ;
43+
44+ }
45+
46+ }
47+ }
48+
49+ // Emitting the event somewhere in your application
50+ // eventEmitter.emit('openai');
51+
52+ let exclusion = { } ;
53+
54+ function generateExclusionList ( ) {
55+ exclusion = { ...require . cache } ;
56+ }
57+
58+ function getModuleDependencies ( modulePath ) {
59+ let moduleObj = require . cache [ modulePath ] ;
60+ if ( ! moduleObj ) {
61+ return [ ] ;
62+ }
63+
64+ // Get all child module paths
65+ return moduleObj . children . map ( child => child . id ) ;
66+ }
67+
68+ function isModuleUsedElsewhere ( modulePath , moduleName ) {
69+ return Object . keys ( require . cache ) . some ( path => {
70+ const moduleObj = require . cache [ path ] ;
71+ return moduleObj . children . some ( child => child . id === modulePath && path !== modulePath ) ;
72+ } ) ;
73+ }
74+
75+ function clearModuleCache ( moduleName ) {
76+ try {
77+ const modulePath = require . resolve ( moduleName ) ;
78+ const dependencies = getModuleDependencies ( modulePath ) ;
79+
80+ // Recursively clear dependencies from cache
81+ dependencies . forEach ( depPath => {
82+ clearModuleCache ( depPath ) ;
83+ } ) ;
84+
85+ // Check if the module is a dependency of other modules
86+ const moduleObj = require . cache [ modulePath ] ;
87+ if ( moduleObj && moduleObj . parent ) {
88+ console . log ( `Module ${ moduleName } is a dependency of other modules.` ) ;
89+ return ;
90+ }
91+
92+ // Check if the module is used by other modules
93+ if ( isModuleUsedElsewhere ( modulePath , moduleName ) ) {
94+ console . log ( `Module ${ moduleName } is a dependency of other modules.` ) ;
95+ return ;
96+ }
97+
98+ // Remove the module from the cache
99+ delete require . cache [ modulePath ] ;
100+ console . log ( `Module ${ moduleName } has been removed from cache.` ) ;
101+ } catch ( error ) {
102+ console . error ( `Error clearing module cache for ${ moduleName } : ${ error . message } ` ) ;
103+ }
104+ }
105+
106+ // Function to create the scripts directory if it doesn't exist
107+ async function createScriptsDirectory ( ) {
108+ try {
109+ await fs . mkdir ( scriptsDirectory , { recursive : true } ) ;
110+ console . log ( `Scripts directory created at ${ scriptsDirectory } ` ) ;
111+ } catch ( error ) {
112+ console . error ( 'Error creating scripts directory:' , error ) ;
113+ throw error ; // Halt execution if directory creation fails
114+ }
115+ }
116+
117+ // Call this function at the start of your application
118+ createScriptsDirectory ( ) ;
119+
120+ // Function to fetch script from database and save to disk
121+ async function fetchScriptFromDatabaseAndSave ( scriptId , pathname ) {
122+ let data = {
123+ method : 'object.read' ,
124+ array : 'files' ,
125+ $filter : {
126+ query : [
127+ { key : "host" , value : [ hostname , '*' ] , operator : "$in" } ,
128+ { key : "pathname" , value : pathname , operator : "$eq" }
129+ ] ,
130+ limit : 1
131+ } ,
132+ organization_id
133+ } ;
134+
135+ let file = await crud . send ( data ) ;
136+ let src ;
137+
138+ if ( file && file . object && file . object [ 0 ] ) {
139+ src = file . object [ 0 ] . src ;
140+ } else {
141+ throw new Error ( 'Script not found in database' ) ;
142+ }
143+
144+ // Save to disk for future use
145+ const scriptPath = path . join ( scriptsDirectory , `${ scriptId } .js` ) ;
146+ await fs . writeFile ( scriptPath , src ) ;
147+
148+ return src ;
149+ }
150+
151+ // Map to track timeouts and contexts for each script
152+ const scriptTimeouts = new Map ( ) ;
153+
154+ // Function to execute a script with a debounce timeout
155+ async function executeScriptWithTimeout ( scriptId , pathname , timeoutDuration = 10000 ) {
156+ let context ;
157+ let scriptContent ;
158+
159+ // Check if the script is already loaded
160+ if ( scriptTimeouts . has ( scriptId ) ) {
161+ clearTimeout ( scriptTimeouts . get ( scriptId ) . timeout ) ;
162+ context = scriptTimeouts . get ( scriptId ) . context ;
163+ } else {
164+ // Check if script exists on disk, else fetch from database
165+ const scriptPath = path . join ( scriptsDirectory , `${ scriptId } .js` ) ;
166+ try {
167+ await fs . access ( scriptPath ) ;
168+ scriptContent = await fs . readFile ( scriptPath , 'utf8' ) ;
169+ } catch {
170+ scriptContent = await fetchScriptFromDatabaseAndSave ( scriptId , pathname ) ;
171+ }
172+
173+ // Execute the script
174+ context = new vm . createContext ( { } ) ;
175+ const script = new vm . Script ( scriptContent ) ;
176+ script . runInContext ( context ) ;
177+ }
178+
179+ // Reset or set the timeout
180+ const timeout = setTimeout ( ( ) => {
181+ for ( const key in context ) {
182+ if ( context . hasOwnProperty ( key ) ) {
183+ delete context [ key ] ;
184+ }
185+ }
186+ scriptTimeouts . delete ( scriptId ) ;
187+ console . log ( `Script ${ scriptId } removed due to inactivity.` ) ;
188+ } , timeoutDuration ) ;
189+
190+ // Update the map
191+ scriptTimeouts . set ( scriptId , { context, timeout } ) ;
192+ }
193+
194+ // Example usage
195+ const scriptId = 'unique-script-id' ;
196+ const pathname = '/path/to/script' ; // Set the appropriate pathname
197+
198+ executeScriptWithTimeout ( scriptId , pathname , 10000 ) . then ( ( ) => {
199+ console . log ( `Script ${ scriptId } executed.` ) ;
200+ } ) ;
201+
202+
203+ // Call this function at the start of your server
204+ // generateExclusionList();
205+
206+ // Example usage
207+ // const moduleName = 'your-module-name';
208+ // clearModuleCache(moduleName);
209+
210+ module . exports = CoCreateLazyLoader ;
0 commit comments