Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ version: "3"
vars:
APP_NAME: node-manager-plugin
BIN_DIR: build
MAINNET_VERSION: "MAIN.4.1"
BUILDNET_VERSION: "DEVN.29.1"
MAINNET_VERSION: "MAIN.4.2"
BUILDNET_VERSION: "DEVN.29.2"
NODE_MASSA_DIR: "build/node-massa"

tasks:
Expand Down
3 changes: 3 additions & 0 deletions api/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import (
func OriginRestrictMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
origin := stationHttpUtils.GetRequestOrigin(r)
if origin == "unknown" {
origin = r.Host
}
hostname := stationHttpUtils.ExtractHostname(origin)

for _, allowedDomain := range allowedDomains() {
Expand Down
2 changes: 1 addition & 1 deletion api/pluginAPI-V0.yml
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ definitions:
Network:
type: object
properties:
version: # network value is contained in the version name. Ex: MAIN.4.1
version: # network value is contained in the version name. Ex: MAIN.4.2
type: string
description: The version of the node network
hasPwd:
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ require (
github.com/ncruces/go-sqlite3 v0.27.1
github.com/stretchr/testify v1.11.1
golang.org/x/net v0.41.0
golang.org/x/sys v0.34.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v2 v2.4.0
)
Expand Down Expand Up @@ -51,6 +50,7 @@ require (
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
)
4 changes: 2 additions & 2 deletions int/config/plugin_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ func init() {
PwdBuildnet: "",
AutoRestart: false,
IsMainnet: true,
MainnetVersion: "MAIN.4.1",
BuildnetVersion: "DEVN.29.1",
MainnetVersion: "MAIN.4.2",
BuildnetVersion: "DEVN.29.2",
}
}

Expand Down
12 changes: 6 additions & 6 deletions int/config/plugin_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ func TestRemoveOldNodeVersionsArtifacts(t *testing.T) {

// Prepare plugin info with current versions
pi := &PluginInfo{
MainnetVersion: "MAIN.4.1",
BuildnetVersion: "DEVN.29.1",
MainnetVersion: "MAIN.4.2",
BuildnetVersion: "DEVN.29.2",
}

// Create directories representing versions
mustMkdir(t, filepath.Join(root, "MAIN.4.1")) // should stay
mustMkdir(t, filepath.Join(root, "DEVN.29.1")) // should stay
mustMkdir(t, filepath.Join(root, "MAIN.4.2")) // should stay
mustMkdir(t, filepath.Join(root, "DEVN.29.2")) // should stay
mustMkdir(t, filepath.Join(root, "MAIN.3.0")) // should be removed
mustMkdir(t, filepath.Join(root, "DEVN.28.16")) // should be removed
mustMkdir(t, filepath.Join(root, "random-other")) // should be removed
Expand All @@ -34,8 +34,8 @@ func TestRemoveOldNodeVersionsArtifacts(t *testing.T) {
}

// Assert expected directories
assertExists(t, filepath.Join(root, "MAIN.4.1"), true)
assertExists(t, filepath.Join(root, "DEVN.29.1"), true)
assertExists(t, filepath.Join(root, "MAIN.4.2"), true)
assertExists(t, filepath.Join(root, "DEVN.29.2"), true)
assertExists(t, filepath.Join(root, "MAIN.3.0"), false)
assertExists(t, filepath.Join(root, "DEVN.28.16"), false)
assertExists(t, filepath.Join(root, "random-other"), false)
Expand Down
9 changes: 8 additions & 1 deletion int/core/node-manager/node-manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,17 @@ func (nodeMana *NodeManager) handleNodeStopped() {
result := <-nodeMana.processExitedChan // Wait for the command to exit
status := nodeStatusPkg.NodeStatusOff

if result.Err != nil && !isUserInterrupted(result.Err) {
currentStatus := nodeMana.GetStatus()
logger.Infof("Current status: %s", currentStatus)

// check whether the node was closed by the user or by a process error
if result.Err != nil && currentStatus != nodeStatusPkg.NodeStatusStopping {
logger.Errorf("massa node process exited with error: %v", result.Err)
status = nodeStatusPkg.NodeStatusCrashed

logger.Info("Cancelling async tasks")
nodeMana.cancelAsyncTask()

// if auto-restart option is enabled, restart the node
if config.GlobalPluginInfo.GetAutoRestart() {
logger.Info("Auto-restarting node due to error")
Expand Down
94 changes: 92 additions & 2 deletions int/core/node-manager/node_log_manager.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package nodeManager

import (
"bytes"
"fmt"
"os"
"path/filepath"
Expand All @@ -24,6 +25,90 @@ type logFile struct {
timestamp *time.Time // nil for the current file
}

var ansiColorRegexp = regexp.MustCompile(`\x1b\[[0-9;]*m`)

// utcFixWrapperLogger wraps a lumberjack.Logger and rewrites the
// timestamp at the beginning of each log line to the current time in
// RFC3339Nano format.
type utcFixWrapperLogger struct {
inner *lumberjack.Logger
buf bytes.Buffer
}

func (w *utcFixWrapperLogger) Close() error {
// Flush any remaining buffered data as a final line.
if w.buf.Len() > 0 {
line := w.buf.String()
w.buf.Reset()
if err := w.writeLine(line); err != nil {
return err
}
}
return w.inner.Close()
}

func (w *utcFixWrapperLogger) Write(p []byte) (int, error) {
total := 0

for len(p) > 0 {
idx := bytes.IndexByte(p, '\n')
if idx == -1 {
// No complete line in this chunk, buffer it.
n, _ := w.buf.Write(p)
total += n
return total, nil
}

// Buffer up to the newline (excluding it).
if idx > 0 {
_, _ = w.buf.Write(p[:idx])
}

line := w.buf.String()
w.buf.Reset()

if err := w.writeLine(line); err != nil {
// We consumed idx+1 bytes from p before failing.
total += idx + 1
return total, err
}

// Skip over the newline we just handled.
p = p[idx+1:]
total += idx + 1
}

return total, nil
}

func (w *utcFixWrapperLogger) writeLine(line string) error {
// Handle Windows-style CRLF: strip trailing '\r' before processing.
line = strings.TrimSuffix(line, "\r")

// If the line is empty, just forward a newline.
if line == "" {
_, err := w.inner.Write([]byte("\n"))
return err
}

now := time.Now().Local().Format(time.RFC3339Nano)

processed := line
if spaceIdx := strings.IndexByte(line, ' '); spaceIdx > 0 {
candidate := line[:spaceIdx]
// Some loggers wrap the timestamp in ANSI color codes; strip them
// before attempting to parse as RFC3339Nano.
cleanCandidate := ansiColorRegexp.ReplaceAllString(candidate, "")
if _, err := time.Parse(time.RFC3339Nano, cleanCandidate); err == nil {
// Replace the existing timestamp (possibly colorized) with the current one.
processed = now + line[spaceIdx:]
}
}

_, err := w.inner.Write([]byte(processed + "\n"))
return err
}

const (
NodeLogFileBaseName = "node"
NodeLogFileExtension = ".log"
Expand Down Expand Up @@ -57,7 +142,7 @@ func (nodeLog *NodeLogManager) cleanOldVersionsLogs() error {
return nil
}

func (nodeLog *NodeLogManager) newLogger(logDirName string) (*lumberjack.Logger, error) {
func (nodeLog *NodeLogManager) newLogger(logDirName string) (*utcFixWrapperLogger, error) {
logFilesFolderPath := filepath.Join(nodeLog.config.NodeLogPath, logDirName)

// Create the log files folder for the given logDirName if it doesn't exist
Expand All @@ -67,10 +152,15 @@ func (nodeLog *NodeLogManager) newLogger(logDirName string) (*lumberjack.Logger,
}
}

return &lumberjack.Logger{
l := &lumberjack.Logger{
Filename: filepath.Join(logFilesFolderPath, NodeLogFileBaseName+NodeLogFileExtension),
MaxSize: nodeLog.config.NodeLogMaxSize, // megabytes
MaxBackups: nodeLog.config.MaxLogBackups,
LocalTime: true,
}

return &utcFixWrapperLogger{
inner: l,
}, nil
}

Expand Down
14 changes: 8 additions & 6 deletions int/core/node-manager/node_log_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,24 @@ func TestNodeLogger(t *testing.T) {
require.NoError(t, err)

version := "test-version"
lumberjackLogger, err := logger.newLogger(version)
wc, err := logger.newLogger(version)
require.NoError(t, err)

tw := wc

// Check if the logger was created with correct settings
assert.NotNil(t, lumberjackLogger)
assert.Equal(t, filepath.Join(tempDir, version, NodeLogFileBaseName+NodeLogFileExtension), lumberjackLogger.Filename)
assert.Equal(t, testConfig.NodeLogMaxSize, lumberjackLogger.MaxSize)
assert.Equal(t, testConfig.MaxLogBackups, lumberjackLogger.MaxBackups)
assert.NotNil(t, tw)
assert.Equal(t, filepath.Join(tempDir, version, NodeLogFileBaseName+NodeLogFileExtension), tw.inner.Filename)
assert.Equal(t, testConfig.NodeLogMaxSize, tw.inner.MaxSize)
assert.Equal(t, testConfig.MaxLogBackups, tw.inner.MaxBackups)

// Check if directory was created
expectedLogPath := filepath.Join(tempDir, version)
_, err = os.Stat(expectedLogPath)
assert.NoError(t, err)

// Write some test content
_, err = lumberjackLogger.Write([]byte("test log content\n"))
_, err = wc.Write([]byte("test log content\n"))
assert.NoError(t, err)

// Check if log file was created
Expand Down
18 changes: 0 additions & 18 deletions int/core/node-manager/unix_utils.go

This file was deleted.

15 changes: 14 additions & 1 deletion int/core/node-manager/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package nodeManager

import (
"errors"
"runtime"
"syscall"

nodeStatusPkg "github.com/massalabs/node-manager-plugin/int/core/NodeStatus"
Expand All @@ -19,7 +20,19 @@ func connRefused(err error) bool {
var errno syscall.Errno

if errors.As(err, &errno) {
return errno == syscall.ECONNREFUSED
// On Unix-like systems, ECONNREFUSED is the standard way to signal
// "connection refused".
if errno == syscall.ECONNREFUSED {
return true
}

// On Windows, network errors come from Winsock (WSAECONNREFUSED = 10061),
// and Go wraps them as syscall.Errno without mapping them to ECONNREFUSED.
// Detect that numeric code explicitly so we correctly treat it as
// "connection refused" while the node API is not yet ready.
if runtime.GOOS == "windows" && errno == syscall.Errno(10061) {
return true
}
}

return false
Expand Down
20 changes: 0 additions & 20 deletions int/core/node-manager/window_utils.go

This file was deleted.

2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
"description": "Massa blockchain official node manager",
"logo": "favicon.svg",
"home": "",
"version": "0.4.4",
"version": "0.4.5",
"apispec": ""
}
4 changes: 2 additions & 2 deletions scripts/ci-setup-node-from-linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
# Downloads zip archives and extracts massa-node and massa-client from the massa/ folder
#
# Usage: ./ci-setup-node-from-linux.sh <MAINNET_VERSION> <BUILDNET_VERSION> <NODE_MASSA_DIR>
# Example: ./ci-setup-node-from-linux.sh "MAIN.4.1" "DEVN.29.1" "build/node-massa"
# Example: ./ci-setup-node-from-linux.sh "MAIN.4.2" "DEVN.29.2" "build/node-massa"

set -e # Exit on any error

# Check if correct number of parameters provided
if [ $# -ne 3 ]; then
echo "Error: This script requires exactly 3 parameters"
echo "Usage: $0 <MAINNET_VERSION> <BUILDNET_VERSION> <NODE_MASSA_DIR>"
echo "Example: $0 \"MAIN.4.1\" \"DEVN.29.1\" \"build/node-massa\""
echo "Example: $0 \"MAIN.4.2\" \"DEVN.29.2\" \"build/node-massa\""
exit 1
fi

Expand Down
4 changes: 2 additions & 2 deletions scripts/setup-node-unix.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
# Should be called by taskfile.
#
# Usage: ./setup-node-unix.sh <MAINNET_VERSION> <BUILDNET_VERSION> <MAINNET_NODEBIN> <BUILDNET_NODEBIN> <NODE_MASSA_DIR>
# Example: ./setup-node-unix.sh "MAIN.4.1" "DEVN.29.1" "massa_MAIN.4.1_release_linux.tar.gz" "massa_DEVN.29.1_release_linux.tar.gz" "build/node-massa"
# Example: ./setup-node-unix.sh "MAIN.4.2" "DEVN.29.2" "massa_MAIN.4.2_release_linux.tar.gz" "massa_DEVN.29.2_release_linux.tar.gz" "build/node-massa"

set -e # Exit on any error

# Check if correct number of parameters provided
if [ $# -ne 5 ]; then
echo "Error: This script requires exactly 5 parameters"
echo "Usage: $0 <MAINNET_VERSION> <BUILDNET_VERSION> <MAINNET_NODEBIN> <BUILDNET_NODEBIN> <NODE_MASSA_DIR>"
echo "Example: $0 \"MAIN.4.1\" \"DEVN.29.1\" \"massa_MAIN.4.1_release_linux.tar.gz\" \"massa_DEVN.29.1_release_linux.tar.gz\" \"build/node-massa\""
echo "Example: $0 \"MAIN.4.2\" \"DEVN.29.2\" \"massa_MAIN.4.2_release_linux.tar.gz\" \"massa_DEVN.29.2_release_linux.tar.gz\" \"build/node-massa\""
exit 1
fi

Expand Down
Loading