-
Notifications
You must be signed in to change notification settings - Fork 2
deweb plugin use the node used by station #342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request enables the DeWeb plugin to use the same Massa node as Station, creating a unified network configuration. The implementation involves refactoring configuration dependencies from Station to DeWeb-server and introducing a NetworkManager that polls Station's network endpoint to synchronize network settings.
- Decoupled DeWeb-server configuration from Station by moving
NetworkInfosstruct todeweb-server/pkg/config - Implemented a NetworkManager that polls Station every 3 seconds to detect network changes and automatically restart the DeWeb server when needed
- Introduced ServerConfigManager to centralize configuration management with caching
Reviewed changes
Copilot reviewed 39 out of 43 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| server/pkg/config/network.go | Moved NetworkInfos struct from Station, changed field name from Network to Name |
| server/pkg/website/read.go | Updated import to use deweb-server config instead of station config |
| server/pkg/webmanager/manager.go | Updated import to use deweb-server config instead of station config |
| server/pkg/mns/mns.go | Updated import to use deweb-server config instead of station config |
| server/pkg/mns/mns_test.go | Updated import to use deweb-server config instead of station config |
| server/int/api/handlers.go | Updated to use NetworkInfos.Name instead of Network field |
| server/int/api/config/config.go | Changed NetworkInfos type to use deweb-server config |
| server/int/api/middlewares.go | Updated import to use deweb-server config instead of station config |
| plugin/int/station/networkManager.go | New file implementing network polling and synchronization with Station |
| plugin/int/server/manager.go | Removed GetConfig method, added debug logs, added 10s sleep in Restart |
| plugin/int/server/config.go | Added ServerConfigManager for centralized config management with caching |
| plugin/int/api/server/handlers.go | Updated handlers to use ServerConfigManager, changed network response structure |
| plugin/int/api/middleware/middleware.go | Moved and reorganized middleware from api package, added domain restriction |
| plugin/int/api/middleware.go | Deleted file, moved to middleware package |
| plugin/int/api/api.go | Integrated NetworkManager, added network sync on startup |
| plugin/home/src/types/server.ts | Changed network field to name, added url field to NetworkInfo |
| plugin/home/src/Status.tsx | New component for displaying server status with network details |
| plugin/home/src/App.tsx | Refactored to use Status component, optimized state updates to reduce re-renders |
| plugin/api/pluginAPI-V0.yml | Added NetworkInfoItem definition, updated ServerStatus to reference it |
| plugin/api/models/*.go | Generated model changes reflecting API spec updates |
| plugin/api/restapi/operations/*.go | Generated operation changes with improved error handling patterns |
| plugin/api/restapi/server.go | Code quality improvements (interface{} to any, better error handling) |
| plugin/api/restapi/embedded_spec.go | Generated spec embedding reflecting API changes |
| plugin/api/restapi/configure_deweb_plugin.go | Added CORS and domain restriction middleware setup |
| plugin/go.mod | Updated station dependency from v0.6.9 to v0.8.3, added rs/cors v1.8.3 |
| plugin/go.sum | Updated checksums for dependency changes |
| plugin/Taskfile.yml | Split build task into build-frontend and build-backend |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func (np *NetworkManager) pollNetwork() { | ||
| response, err := np.fetchStationNetwork() | ||
| if err != nil { | ||
| logger.Errorf("Failed to fetch station network: %v", err) | ||
| return | ||
| } | ||
|
|
||
| currentConfig, err := np.configManager.GetServerConfig() | ||
| if err != nil { | ||
| logger.Errorf("Failed to get server config: %v", err) | ||
| return | ||
| } | ||
|
|
||
| // if the network on station has changed, update the server config | ||
| if response.URL != currentConfig.NetworkInfos.NodeURL || response.Name != currentConfig.NetworkInfos.Name { | ||
| logger.Infof( | ||
| "Changing massa node configuration from '%s' (%s) to '%s' (%s, the node currently used by station)", | ||
| currentConfig.NetworkInfos.Name, | ||
| currentConfig.NetworkInfos.NodeURL, | ||
| response.Name, | ||
| response.URL, | ||
| ) | ||
|
|
||
| // stop the deweb server | ||
| if err := np.serverManager.Stop(); err != nil && err != server.ErrServerNotRunning { | ||
| logger.Errorf("Failed to stop server: %v", err) | ||
| return | ||
| } | ||
|
|
||
| // update the server config with the new network url | ||
| // Stopping the server can take a few seconds so use this time to update the server config. | ||
| conf := *currentConfig | ||
| conf.NetworkInfos = msConfig.NetworkInfos{ | ||
| NodeURL: response.URL, | ||
| Name: response.Name, | ||
| Version: response.Version, | ||
| ChainID: uint64(response.ChainID), | ||
| } | ||
| if err := np.configManager.SaveServerConfig(&conf); err != nil { | ||
| logger.Errorf("Failed to save server config: %v", err) | ||
| return | ||
| } | ||
|
|
||
| // start the server with the new network url | ||
| if err := np.serverManager.Start(); err != nil { | ||
| logger.Errorf("Failed to start server: %v", err) | ||
| return | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /* | ||
| Retrieve current network information from station and update the deweb | ||
| server config file if the network is not the same. | ||
| */ | ||
| func (np *NetworkManager) SyncServerConfNetworkWithStation() (bool, error) { | ||
| response, err := np.fetchStationNetwork() | ||
| if err != nil { | ||
| return false, err | ||
| } | ||
|
|
||
| currentConfig, err := np.configManager.GetServerConfig() | ||
| if err != nil { | ||
| return false, err | ||
| } | ||
|
|
||
| // if the network on station has changed, update the server config | ||
| if response.URL != currentConfig.NetworkInfos.NodeURL || response.Name != currentConfig.NetworkInfos.Name { | ||
| logger.Infof( | ||
| "Changing massa node configuration from '%s' (%s) to '%s' (%s, the node currently used by station)", | ||
| currentConfig.NetworkInfos.Name, | ||
| currentConfig.NetworkInfos.NodeURL, | ||
| response.Name, | ||
| response.URL, | ||
| ) | ||
|
|
||
| // update the server config with the new network url | ||
| conf := *currentConfig | ||
| conf.NetworkInfos = msConfig.NetworkInfos{ | ||
| NodeURL: response.URL, | ||
| Name: response.Name, | ||
| Version: response.Version, | ||
| ChainID: uint64(response.ChainID), | ||
| } | ||
| if err := np.configManager.SaveServerConfig(&conf); err != nil { | ||
| return false, err | ||
| } | ||
| return true, nil | ||
| } | ||
|
|
||
| return false, nil | ||
| } |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is significant code duplication between pollNetwork (lines 99-148) and SyncServerConfNetworkWithStation (lines 154-190). The network change detection logic and config update code are nearly identical. Consider extracting a common helper method to update the network configuration, which both methods can call.
| type ServerConfigManager struct { | ||
| serverConfig *config.ServerConfig | ||
| configDir string | ||
| } | ||
|
|
||
| // NewServerConfigManager creates a new ServerConfigManager | ||
| func NewServerConfigManager(configDir string) *ServerConfigManager { | ||
| return &ServerConfigManager{ | ||
| configDir: configDir, | ||
| } | ||
| } | ||
|
|
||
| // SaveServerConfig saves a ServerConfig to the given path | ||
| func (c *ServerConfigManager) SaveServerConfig(serverConfig *config.ServerConfig) error { | ||
| if serverConfig == nil { | ||
| return fmt.Errorf("new server config is nil, cannot save it") | ||
| } | ||
|
|
||
| yamlConfig := convertToYamlConfig(serverConfig) | ||
| logger.Infof("Saving server config: %+v", yamlConfig) | ||
|
|
||
| if err := saveYamlConfig(yamlConfig, getConfigPath(c.configDir)); err != nil { | ||
| return fmt.Errorf("failed to save server config: %w", err) | ||
| } | ||
|
|
||
| // Update the cached server config | ||
| c.serverConfig = serverConfig | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // GetServerConfig returns the cached server config | ||
| func (c *ServerConfigManager) GetServerConfig() (*config.ServerConfig, error) { | ||
| if c.serverConfig == nil { | ||
| serverConfig, err := loadConfig(getConfigPath(c.configDir)) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to load server config: %w", err) | ||
| } | ||
|
|
||
| c.serverConfig = serverConfig | ||
| } | ||
|
|
||
| return c.serverConfig, nil | ||
| } |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ServerConfigManager lacks thread-safety mechanisms. The serverConfig field is accessed and modified by multiple goroutines (pollNetwork, SyncServerConfNetworkWithStation, and API handlers) without synchronization. This could lead to race conditions when reading and writing the cached config. Consider adding a mutex to protect concurrent access to serverConfig.
| logger.Infof("Waiting for server to stop isRunning: %v", m.isRunning) | ||
| for time.Now().Before(timeout) && m.isRunning { | ||
| time.Sleep(100 * time.Millisecond) | ||
| } | ||
|
|
||
| logger.Infof("Server stopped after timeout: %v", m.isRunning) | ||
|
|
||
| // If still running after timeout, force kill | ||
| if m.isRunning { | ||
| _ = m.kill() | ||
| logger.Infof("Server stopped after kill: %v", m.isRunning) |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple debug log statements have been added (lines 172, 177, 182) that appear to be temporary debugging code. These should either be removed before merging or converted to appropriate log levels if they provide value for production diagnostics.
| // NetworkPoller periodically polls Station for network information | ||
| type NetworkManager struct { |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment on line 30 still references "NetworkPoller" but should be updated to "NetworkManager" to match the actual type name defined on line 31.
| "(buildnet)"; | ||
|
|
||
| if (status === "running" && network) { | ||
| return `Connected to '${network.name}' node ${networkTypePrecision} ; version: ${network.version || ''}`; |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a grammatical issue with extra spacing between the word "node" and the semicolon. The text should be "Connected to '{network.name}' node {networkTypePrecision}; version:" without the extra space before the semicolon.
| return `Connected to '${network.name}' node ${networkTypePrecision} ; version: ${network.version || ''}`; | |
| return `Connected to '${network.name}' node ${networkTypePrecision}; version: ${network.version || ''}`; |
| handleCORS := cors.New(cors.Options{ | ||
| AllowedMethods: []string{http.MethodGet, http.MethodPut}, | ||
| AllowedOrigins: dewebmiddleware.AllowedDomainsList(), | ||
| }).Handler | ||
|
|
||
| // Middleware chain: CORS → WebAppMiddleware → DomainRestrictionMiddleware → API handlers | ||
| return handleCORS(dewebmiddleware.WebAppMiddleware(dewebmiddleware.DomainRestrictionMiddleware(handler))) |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CORS middleware is configured with AllowedOrigins but uses a whitelist approach via DomainRestrictionMiddleware. These two mechanisms overlap and could lead to confusion. The CORS AllowedOrigins setting will allow preflight requests from these domains, but then DomainRestrictionMiddleware checks the origin again. Consider consolidating this logic or clearly documenting why both are necessary.
| return err | ||
| } | ||
|
|
||
| time.Sleep(10 * time.Second) |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A hardcoded 10-second sleep is added to the Restart method without explanation. This significantly delays server restarts and could negatively impact user experience. If this delay is necessary for the server to fully shut down, consider using a more intelligent approach such as polling the server status or waiting for specific conditions, or at least document why this specific duration is required.
| // NewNetworkPoller creates a new network poller instance | ||
| func NewNetworkManager(configManager *server.ServerConfigManager, serverManager *server.ServerManager) *NetworkManager { |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function comment on line 40 still references "NewNetworkPoller" but the actual function name is "NewNetworkManager". This should be updated for consistency.
| if err != nil { | ||
| return createErrorResponse(http.StatusInternalServerError, "Failed to get server config") | ||
| } | ||
| logger.Infof("Server config: %+v", serverConfig) |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A debug log statement has been added that appears to be temporary debugging code. This should either be removed before merging or converted to an appropriate log level if it provides value for production diagnostics.
| func (np *NetworkManager) Stop() { | ||
| np.mu.Lock() | ||
| defer np.mu.Unlock() | ||
|
|
||
| if !np.isRunning { | ||
| return | ||
| } | ||
|
|
||
| close(np.stopChan) | ||
| np.isRunning = false | ||
| } |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Stop method has a potential race condition. The isRunning flag is protected by a mutex, but after unlocking at line 92, a goroutine in the pollNetwork method could still access isRunning or close the already-closed stopChan. Consider adding a sync.Once to ensure stopChan is only closed once, or restructure the synchronization to wait for the goroutine to finish.
No description provided.