@@ -11,6 +11,7 @@ import (
1111 "sync"
1212
1313 "github.com/mirkobrombin/goup/internal/config"
14+ "github.com/mirkobrombin/goup/internal/logger"
1415 "github.com/mirkobrombin/goup/internal/server/middleware"
1516 log "github.com/sirupsen/logrus"
1617)
@@ -19,6 +20,7 @@ import (
1920type NodeJSPlugin struct {
2021 mu sync.Mutex
2122 process * os.Process
23+ logger * log.Logger
2224}
2325
2426// Name returns the name of the plugin.
@@ -32,8 +34,17 @@ func (p *NodeJSPlugin) Init(mwManager *middleware.MiddlewareManager) error {
3234}
3335
3436// InitForSite initializes the plugin for a specific site.
35- func (p * NodeJSPlugin ) InitForSite (mwManager * middleware.MiddlewareManager , logger * log.Logger , conf config.SiteConfig ) error {
36- mwManager .Use (p .nodeMiddleware (logger , conf ))
37+ func (p * NodeJSPlugin ) InitForSite (mwManager * middleware.MiddlewareManager , baseLogger * log.Logger , conf config.SiteConfig ) error {
38+ // Create a dedicated logger for this plugin/site.
39+ pluginLogger , err := logger .NewPluginLogger (conf .Domain , p .Name ())
40+ if err != nil {
41+ baseLogger .Errorf ("Failed to create NodeJSPlugin logger: %v" , err )
42+ return err
43+ }
44+ p .logger = pluginLogger
45+
46+ // Add the Node.js middleware to intercept matching requests.
47+ mwManager .Use (p .nodeMiddleware (pluginLogger , conf ))
3748 return nil
3849}
3950
@@ -49,18 +60,21 @@ type NodeJSPluginConfig struct {
4960 ProxyPaths []string `json:"proxy_paths"`
5061}
5162
52- // nodeMiddleware intercepts requests and forwards API calls to Node.js.
53- func (p * NodeJSPlugin ) nodeMiddleware (logger * log.Logger , conf config.SiteConfig ) middleware.MiddlewareFunc {
63+ // nodeMiddleware intercepts requests and forwards them to Node.js if they
64+ // match ProxyPaths.
65+ func (p * NodeJSPlugin ) nodeMiddleware (baseLogger * log.Logger , conf config.SiteConfig ) middleware.MiddlewareFunc {
5466 return func (next http.Handler ) http.Handler {
5567 return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
56- // Retrieve site-specific plugin configuration.
68+
69+ // Retrieve plugin config for the current site.
5770 pluginConfigRaw , ok := conf .PluginConfigs [p .Name ()]
5871 if ! ok {
72+ // If there's no configuration for this plugin, just move on.
5973 next .ServeHTTP (w , r )
6074 return
6175 }
6276
63- // Parse configuration .
77+ // Map the raw config to a strong type .
6478 pluginConfig := NodeJSPluginConfig {}
6579 if rawMap , ok := pluginConfigRaw .(map [string ]interface {}); ok {
6680 if enable , ok := rawMap ["enable" ].(bool ); ok {
@@ -93,45 +107,45 @@ func (p *NodeJSPlugin) nodeMiddleware(logger *log.Logger, conf config.SiteConfig
93107 }
94108 }
95109
110+ // If disabled, do nothing.
96111 if ! pluginConfig .Enable {
97- logger .Infof ("NodeJS Plugin is disabled for host: %s" , r .Host )
112+ baseLogger .Infof ("NodeJS Plugin disabled for host: %s" , r .Host )
98113 next .ServeHTTP (w , r )
99114 return
100115 }
101116
102- // Start Node.js if it is not already running.
103- p .ensureNodeServerRunning (pluginConfig , logger )
117+ // Ensure Node.js is running.
118+ p .ensureNodeServerRunning (pluginConfig )
104119
105- // Check if the request should be forwarded to Node.js.
120+ // Check if the request path should be forwarded to Node.js.
106121 for _ , proxyPath := range pluginConfig .ProxyPaths {
107122 if strings .HasPrefix (r .URL .Path , proxyPath ) {
108- p .proxyToNode (w , r , pluginConfig , logger )
123+ p .proxyToNode (w , r , pluginConfig )
109124 return
110125 }
111126 }
112127
113- // If the request does not match a Node.js route, let GoUp handle static files.
128+ // If it doesn't match, serve static files as usual .
114129 next .ServeHTTP (w , r )
115130 })
116131 }
117132}
118133
119134// ensureNodeServerRunning starts Node.js if it is not already running.
120- func (p * NodeJSPlugin ) ensureNodeServerRunning (config NodeJSPluginConfig , logger * log. Logger ) {
135+ func (p * NodeJSPlugin ) ensureNodeServerRunning (config NodeJSPluginConfig ) {
121136 p .mu .Lock ()
122137 defer p .mu .Unlock ()
123138
124139 // If the process is already running, do nothing.
125140 if p .process != nil {
126- logger .Infof ("Node.js server is already running (PID: %d)" , p .process .Pid )
127141 return
128142 }
129143
130- logger .Infof ("Starting Node.js server..." )
144+ p . logger .Infof ("Starting Node.js server..." )
131145
132146 // Install dependencies if required.
133147 if config .InstallDeps {
134- p .installDependencies (config , logger )
148+ p .installDependencies (config )
135149 }
136150
137151 // Start the Node.js server.
@@ -144,35 +158,46 @@ func (p *NodeJSPlugin) ensureNodeServerRunning(config NodeJSPluginConfig, logger
144158
145159 cmd := exec .Command (nodePath , entryPath )
146160 cmd .Dir = config .RootDir
147- cmd .Stdout = os .Stdout
148- cmd .Stderr = os .Stderr
161+
162+ // Redirect the Node.js output to the plugin logger instead of stdout.
163+ cmd .Stdout = p .logger .Writer ()
164+ cmd .Stderr = p .logger .Writer ()
149165
150166 if err := cmd .Start (); err != nil {
151- logger .Errorf ("Failed to start Node.js server: %v" , err )
167+ p . logger .Errorf ("Failed to start Node.js server: %v" , err )
152168 return
153169 }
154170
171+ // Store the process to avoid multiple starts.
155172 p .process = cmd .Process
156- logger .Infof ("Started Node.js server (PID: %d) on port %s" , p .process .Pid , config .Port )
173+
174+ p .logger .Infof ("Started Node.js server (PID: %d) on port %s" , p .process .Pid , config .Port )
175+
176+ // Optionally, handle process exit to close the writers.
177+ go func () {
178+ err := cmd .Wait ()
179+ p .logger .Infof ("Node.js server exited (PID: %d), error=%v" , p .process .Pid , err )
180+ // Close the logger writers to free resources.
181+ p .logger .Writer ().Close ()
182+ }()
157183}
158184
159- // proxyToNode forwards the original request to Node.js and returns the response.
160- func ( p * NodeJSPlugin ) proxyToNode ( w http. ResponseWriter , r * http. Request , config NodeJSPluginConfig , logger * log. Logger ) {
161- // Construct the URL for forwarding the request to Node.js.
185+ // proxyToNode forwards the original HTTP request to Node.js and sends back
186+ // the response.
187+ func ( p * NodeJSPlugin ) proxyToNode ( w http. ResponseWriter , r * http. Request , config NodeJSPluginConfig ) {
162188 nodeURL := fmt .Sprintf ("http://localhost:%s%s" , config .Port , r .URL .Path )
163189
164- // Create a new HTTP request forwarding the original request data.
165190 bodyReader , err := io .ReadAll (r .Body )
166191 if err != nil {
167- logger .Errorf ("Failed to read request body: %v" , err )
192+ p . logger .Errorf ("Failed to read request body: %v" , err )
168193 http .Error (w , "Failed to read request body" , http .StatusInternalServerError )
169194 return
170195 }
171196 defer r .Body .Close ()
172197
173198 req , err := http .NewRequest (r .Method , nodeURL , strings .NewReader (string (bodyReader )))
174199 if err != nil {
175- logger .Errorf ("Failed to create request for Node.js: %v" , err )
200+ p . logger .Errorf ("Failed to create request for Node.js: %v" , err )
176201 http .Error (w , "Failed to create request" , http .StatusInternalServerError )
177202 return
178203 }
@@ -187,13 +212,13 @@ func (p *NodeJSPlugin) proxyToNode(w http.ResponseWriter, r *http.Request, confi
187212 client := & http.Client {}
188213 resp , err := client .Do (req )
189214 if err != nil {
190- logger .Errorf ("Failed to connect to Node.js backend: %v" , err )
215+ p . logger .Errorf ("Failed to connect to Node.js backend: %v" , err )
191216 http .Error (w , "Node.js backend unavailable" , http .StatusBadGateway )
192217 return
193218 }
194219 defer resp .Body .Close ()
195220
196- // Copy response headers.
221+ // Forward response headers back to the client .
197222 for key , values := range resp .Header {
198223 for _ , value := range values {
199224 w .Header ().Add (key , value )
@@ -204,61 +229,35 @@ func (p *NodeJSPlugin) proxyToNode(w http.ResponseWriter, r *http.Request, confi
204229 w .WriteHeader (resp .StatusCode )
205230 body , err := io .ReadAll (resp .Body )
206231 if err != nil {
207- logger .Errorf ("Failed to read response body from Node.js: %v" , err )
232+ p . logger .Errorf ("Failed to read response body from Node.js: %v" , err )
208233 http .Error (w , "Failed to read response from Node.js" , http .StatusInternalServerError )
209234 return
210235 }
211236
212237 w .Write (body )
213238}
214239
215- // startNodeServer ensures the Node.js server is running.
216- func (p * NodeJSPlugin ) startNodeServer (config NodeJSPluginConfig , logger * log.Logger ) {
217- logger .Infof ("Starting Node.js server..." )
218- p .mu .Lock ()
219- defer p .mu .Unlock ()
220-
221- // Install dependencies if needed.
222- if config .InstallDeps {
223- p .installDependencies (config , logger )
224- }
225-
226- // Start the Node.js server.
227- entryPath := filepath .Join (config .RootDir , config .Entry )
228- cmd := exec .Command (config .NodePath , entryPath )
229- cmd .Dir = config .RootDir
230- cmd .Stdout = os .Stdout
231- cmd .Stderr = os .Stderr
232-
233- if err := cmd .Start (); err != nil {
234- logger .Errorf ("Failed to start Node.js server: %v" , err )
235- return
236- }
237-
238- p .process = cmd .Process
239- logger .Infof ("Started Node.js server (PID: %d) on port %s" , p .process .Pid , config .Port )
240- }
241-
242240// installDependencies installs dependencies using the configured package manager.
243- func (p * NodeJSPlugin ) installDependencies (config NodeJSPluginConfig , logger * log. Logger ) {
241+ func (p * NodeJSPlugin ) installDependencies (config NodeJSPluginConfig ) {
244242 nodeModulesPath := filepath .Join (config .RootDir , "node_modules" )
245243 if _ , err := os .Stat (nodeModulesPath ); os .IsNotExist (err ) {
246- logger .Infof ("node_modules not found, installing dependencies in %s" , config .RootDir )
244+ p . logger .Infof ("node_modules not found, installing dependencies in %s" , config .RootDir )
247245
248246 packageManager := config .PackageManager
249247 if packageManager == "" {
250248 packageManager = "npm"
251249 }
252250
253- logger .Infof ("Using package manager: %s" , packageManager )
251+ p . logger .Infof ("Using package manager: %s" , packageManager )
254252 cmd := exec .Command (packageManager , "install" )
255253 cmd .Dir = config .RootDir
256- cmd .Stdout = os .Stdout
257- cmd .Stderr = os .Stderr
254+ cmd .Stdout = p .logger .Writer ()
255+ cmd .Stderr = p .logger .Writer ()
256+
258257 if err := cmd .Run (); err != nil {
259- logger .Errorf ("Failed to install dependencies using %s: %v" , packageManager , err )
258+ p . logger .Errorf ("Failed to install dependencies using %s: %v" , packageManager , err )
260259 } else {
261- logger .Infof ("Dependencies installed successfully using %s" , packageManager )
260+ p . logger .Infof ("Dependencies installed successfully using %s" , packageManager )
262261 }
263262 }
264263}
0 commit comments