1- const EventEmitter = require ( 'events' ) ;
2- const eventEmitter = new EventEmitter ( ) ;
31const fs = require ( 'fs' ) . promises ;
42const path = require ( 'path' ) ;
53const vm = require ( 'vm' ) ;
64const Config = require ( "@cocreate/config" ) ;
5+ const { URL } = require ( 'url' ) ;
6+
7+ const organizations = { } ;
8+ const hosts = { } ;
79
810class CoCreateLazyLoader {
9- constructor ( crud ) {
11+ constructor ( server , crud , files ) {
12+ this . server = server
1013 this . wsManager = crud . wsManager
1114 this . crud = crud
15+ this . files = files
1216 this . exclusion = { ...require . cache } ;
1317 this . modules = { } ;
1418 this . init ( )
@@ -30,70 +34,160 @@ class CoCreateLazyLoader {
3034 // Call this function at the start of your application
3135 createScriptsDirectory ( ) ;
3236
33- const config = await Config ( 'lazyload' , false , false )
37+ // TODO: return the value so it can be applied directly to modules
38+ // this.modules[key] = await Config('modules', false, false)
39+
40+ const config = await Config ( 'modules' , false , false )
3441 if ( ! config )
3542 return
3643
37- for ( let key of Object . keys ( config . lazyload ) ) {
38- let moduleConfig = config . lazyload [ key ] ;
39- eventEmitter . on ( moduleConfig . event , async ( ) => {
40- this . executeScriptWithTimeout ( key , moduleConfig )
44+ for ( let name of Object . keys ( config . modules ) ) {
45+ this . modules [ name ] = config . modules [ name ] ;
46+ this . wsManager . on ( this . modules [ name ] . event , async ( data ) => {
47+ this . executeScriptWithTimeout ( name , data )
4148 } ) ;
4249 }
4350
44- // eventEmitter.emit('openai');
51+ this . server . on ( 'request' , async ( req , res ) => {
52+ try {
53+ const valideUrl = new URL ( `http://${ req . headers . host } ${ req . url } ` ) ;
54+ const hostname = valideUrl . hostname ;
55+
56+ let organization = hosts . get ( hostname ) ;
57+ if ( ! organization ) {
58+ let org = await this . crud . send ( {
59+ method : 'object.read' ,
60+ array : 'organizations' ,
61+ $filter : {
62+ query : [
63+ { key : "host" , value : [ hostname ] , operator : "$in" }
64+ ]
65+ } ,
66+ organization_id : process . env . organization_id
67+ } )
68+
69+ if ( ! org || ! org . object || ! org . object [ 0 ] ) {
70+ if ( ! hostNotFound )
71+ hostNotFound = await getDefaultFile ( '/hostNotFound.html' )
72+ return sendResponse ( hostNotFound . object [ 0 ] . src , 404 , { 'Content-Type' : 'text/html' , 'storage' : organization . storage } )
73+ } else {
74+ organization = org . object [ 0 ]
75+ organizations [ organization . _id ] = organization
76+ hosts [ hostname ] = organization
77+ }
78+ }
79+
80+ if ( valideUrl . pathname . startsWith ( '/webhooks/' ) ) {
81+ let name = req . url . split ( '/' ) [ 2 ] ; // Assuming URL structure is /webhook/name/...
82+ if ( this . modules [ name ] ) {
83+ this . executeScriptWithTimeout ( name , { req, res, crud : this . crud , organization, valideUrl } )
84+ } else {
85+ // Handle unknown module or missing webhook method
86+ res . writeHead ( 404 , { 'Content-Type' : 'application/json' } ) ;
87+ res . end ( JSON . stringify ( { error : 'Not found' } ) ) ;
88+ }
89+
90+ } else {
91+ this . files . send ( req , res , this . crud , organization , valideUrl )
92+ }
93+
94+ } catch ( error ) {
95+ res . writeHead ( 400 , { 'Content-Type' : 'text/plain' } ) ;
96+ res . end ( 'Invalid host format' ) ;
97+ }
98+
99+
100+ } )
45101
46102 }
47103
48- async executeScriptWithTimeout ( moduleName , moduleConfig ) {
104+ async executeScriptWithTimeout ( name , data ) {
49105 try {
50- if ( ! moduleConfig . content ) {
51- if ( moduleConfig . path )
52- moduleConfig . content = await require ( moduleConfig . path )
106+ if ( ! this . modules [ name ] . content ) {
107+ if ( this . modules [ name ] . path )
108+ this . modules [ name ] . content = await require ( this . modules [ name ] . path )
53109 else {
54110 try {
55- const scriptPath = path . join ( scriptsDirectory , `${ moduleName } .js` ) ;
111+ const scriptPath = path . join ( scriptsDirectory , `${ name } .js` ) ;
56112 await fs . access ( scriptPath ) ;
57- moduleConfig . content = await fs . readFile ( scriptPath , 'utf8' ) ;
113+ this . modules [ name ] . content = await fs . readFile ( scriptPath , 'utf8' ) ;
58114 } catch {
59- moduleConfig . content = await fetchScriptFromDatabaseAndSave ( moduleName , moduleConfig ) ;
115+ this . modules [ name ] . content = await fetchScriptFromDatabaseAndSave ( name , this . modules [ name ] , data ) ;
60116 }
61117 }
62118 }
63119
64- if ( moduleConfig . unload === false || moduleConfig . unload === 'false' )
120+ if ( this . modules [ name ] . content ) {
121+ data . apis = await this . getApiKey ( data . organization_id , name )
122+ data = await this . modules [ name ] . content . send ( data )
123+ delete data . apis
124+ if ( data . socket )
125+ this . wsManager . send ( data )
126+ } else
65127 return
66- else if ( moduleConfig . unload === true || moduleConfig . unload === 'true' )
128+
129+ if ( this . modules [ name ] . unload === false || this . modules [ name ] . unload === 'false' )
130+ return
131+ else if ( this . modules [ name ] . unload === true || this . modules [ name ] . unload === 'true' )
67132 console . log ( 'config should unload after completeion ' )
68- else if ( moduleConfig . unload = parseInt ( moduleConfig . unload , 10 ) ) {
133+ else if ( this . modules [ name ] . unload = parseInt ( this . modules [ name ] . unload , 10 ) ) {
69134 // Check if the script is already loaded
70- if ( moduleConfig . timeout ) {
71- clearTimeout ( moduleConfig . timeout ) ;
72- } else if ( ! moduleConfig . path ) {
135+ if ( this . modules [ name ] . timeout ) {
136+ clearTimeout ( this . modules [ name ] . timeout ) ;
137+ } else if ( ! this . modules [ name ] . path ) {
73138 // Execute the script
74- moduleConfig . context = new vm . createContext ( { } ) ;
75- const script = new vm . Script ( moduleConfig . context ) ;
139+ this . modules [ name ] . context = new vm . createContext ( { } ) ;
140+ const script = new vm . Script ( this . modules [ name ] . context ) ;
76141 script . runInContext ( context ) ;
77142 }
78143
79144 // Reset or set the timeout
80145 const timeout = setTimeout ( ( ) => {
81- delete this . modules [ moduleName ]
82- delete moduleConfig . timeout
83- delete moduleConfig . context
84- delete moduleConfig . content
85- console . log ( `Module ${ moduleName } removed due to inactivity.` ) ;
86- clearModuleCache ( moduleName ) ;
146+ // delete this.modules[name ]
147+ delete this . modules [ name ] . timeout
148+ delete this . modules [ name ] . context
149+ delete this . modules [ name ] . content
150+ console . log ( `Module ${ name } removed due to inactivity.` ) ;
151+ clearModuleCache ( name ) ;
87152
88- } , moduleConfig . unload ) ;
153+ } , this . modules [ name ] . unload ) ;
89154
90- moduleConfig . timeout = timeout
155+ this . modules [ name ] . timeout = timeout
91156 }
92157 } catch ( error ) {
93158 console . log ( error )
94159 }
95160 }
96161
162+ async getApiKey ( organization_id , name ) {
163+ organizations [ organization_id ] = this . getOrganization ( organization_id , name )
164+ organizations [ organization_id ] = await organizations [ organization_id ]
165+ return organizations [ organization_id ] [ name ]
166+ }
167+
168+ async getOrganization ( organization_id ) {
169+ let organization = await this . crud . send ( {
170+ method : 'object.read' ,
171+ database : organization_id ,
172+ array : 'organizations' ,
173+ object : [ { _id : organization_id } ] ,
174+ organization_id
175+ } )
176+
177+ if ( organization
178+ && organization . object
179+ && organization . object [ 0 ] ) {
180+ if ( organization . object [ 0 ] . apis ) {
181+ return organization . object [ 0 ] . apis
182+ } else
183+ return { error : 'No apis defined could not be found' }
184+ } else {
185+ return { serverOrganization : false , error : 'An organization could not be found' }
186+ }
187+
188+ }
189+
190+
97191}
98192
99193function getModuleDependencies ( modulePath ) {
@@ -106,7 +200,7 @@ function getModuleDependencies(modulePath) {
106200 return moduleObj . children . map ( child => child . id ) ;
107201}
108202
109- function isModuleUsedElsewhere ( modulePath , moduleName ) {
203+ function isModuleUsedElsewhere ( modulePath , name ) {
110204 return Object . keys ( require . cache ) . some ( path => {
111205 const moduleObj = require . cache [ path ] ;
112206 // return moduleObj.children.some(child => child.id === modulePath && path !== modulePath);
@@ -119,39 +213,39 @@ function isModuleUsedElsewhere(modulePath, moduleName) {
119213 } ) ;
120214}
121215
122- function clearModuleCache ( moduleName ) {
216+ function clearModuleCache ( name ) {
123217 try {
124- const modulePath = require . resolve ( moduleName ) ;
218+ const modulePath = require . resolve ( name ) ;
125219 const dependencies = getModuleDependencies ( modulePath ) ;
126220
127221 // Check if the module is a dependency of other modules
128222 // const moduleObj = require.cache[modulePath];
129223 // if (moduleObj && moduleObj.parent) {
130- // console.log(`Module ${moduleName } is a dependency of other modules.`);
224+ // console.log(`Module ${name } is a dependency of other modules.`);
131225 // return;
132226 // }
133227
134228 // Check if the module is used by other modules
135- if ( isModuleUsedElsewhere ( modulePath , moduleName ) ) {
136- console . log ( `Module ${ moduleName } is a dependency of other modules.` ) ;
229+ if ( isModuleUsedElsewhere ( modulePath , name ) ) {
230+ console . log ( `Module ${ name } is a dependency of other modules.` ) ;
137231 return ;
138232 }
139233
140234 // Remove the module from the cache
141235 delete require . cache [ modulePath ] ;
142- console . log ( `Module ${ moduleName } has been removed from cache.` ) ;
236+ console . log ( `Module ${ name } has been removed from cache.` ) ;
143237 // Recursively clear dependencies from cache
144238 dependencies . forEach ( depPath => {
145239 clearModuleCache ( depPath ) ;
146240 } ) ;
147241
148242 } catch ( error ) {
149- console . error ( `Error clearing module cache for ${ moduleName } : ${ error . message } ` ) ;
243+ console . error ( `Error clearing module cache for ${ name } : ${ error . message } ` ) ;
150244 }
151245}
152246
153247// Function to fetch script from database and save to disk
154- async function fetchScriptFromDatabaseAndSave ( moduleName , moduleConfig ) {
248+ async function fetchScriptFromDatabaseAndSave ( name , moduleConfig ) {
155249 let data = {
156250 method : 'object.read' ,
157251 array : moduleConfig . array ,
@@ -165,7 +259,7 @@ async function fetchScriptFromDatabaseAndSave(moduleName, moduleConfig) {
165259 organization_id
166260 } ;
167261
168- let file = await crud . send ( data ) ;
262+ let file = await this . crud . send ( data ) ;
169263 let src ;
170264
171265 if ( file && file . object && file . object [ 0 ] ) {
@@ -175,7 +269,7 @@ async function fetchScriptFromDatabaseAndSave(moduleName, moduleConfig) {
175269 }
176270
177271 // Save to disk for future use
178- const scriptPath = path . join ( scriptsDirectory , `${ moduleName } .js` ) ;
272+ const scriptPath = path . join ( scriptsDirectory , `${ name } .js` ) ;
179273 await fs . writeFile ( scriptPath , src ) ;
180274
181275 return src ;
0 commit comments