Skip to content

Conversation

@fleandrei
Copy link
Contributor

No description provided.

Copy link

Copilot AI left a 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 NetworkInfos struct to deweb-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.

Comment on lines +99 to +190
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
}
Copy link

Copilot AI Jan 9, 2026

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.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +62
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
}
Copy link

Copilot AI Jan 9, 2026

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.

Copilot uses AI. Check for mistakes.
Comment on lines +172 to +182
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)
Copy link

Copilot AI Jan 9, 2026

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.

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +31
// NetworkPoller periodically polls Station for network information
type NetworkManager struct {
Copy link

Copilot AI Jan 9, 2026

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.

Copilot uses AI. Check for mistakes.
"(buildnet)";

if (status === "running" && network) {
return `Connected to '${network.name}' node ${networkTypePrecision} ; version: ${network.version || ''}`;
Copy link

Copilot AI Jan 9, 2026

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.

Suggested change
return `Connected to '${network.name}' node ${networkTypePrecision} ; version: ${network.version || ''}`;
return `Connected to '${network.name}' node ${networkTypePrecision}; version: ${network.version || ''}`;

Copilot uses AI. Check for mistakes.
Comment on lines +109 to +115
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)))
Copy link

Copilot AI Jan 9, 2026

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.

Copilot uses AI. Check for mistakes.
return err
}

time.Sleep(10 * time.Second)
Copy link

Copilot AI Jan 9, 2026

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.

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +41
// NewNetworkPoller creates a new network poller instance
func NewNetworkManager(configManager *server.ServerConfigManager, serverManager *server.ServerManager) *NetworkManager {
Copy link

Copilot AI Jan 9, 2026

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.

Copilot uses AI. Check for mistakes.
if err != nil {
return createErrorResponse(http.StatusInternalServerError, "Failed to get server config")
}
logger.Infof("Server config: %+v", serverConfig)
Copy link

Copilot AI Jan 9, 2026

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.

Copilot uses AI. Check for mistakes.
Comment on lines +83 to +93
func (np *NetworkManager) Stop() {
np.mu.Lock()
defer np.mu.Unlock()

if !np.isRunning {
return
}

close(np.stopChan)
np.isRunning = false
}
Copy link

Copilot AI Jan 9, 2026

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.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants