Skip to content

Commit cf8bf5a

Browse files
authored
Handle Node.js Debug Messages and Improve Port Termination (#99)
* chore: Remove unrelated code, clean up all the things * chore: ⚡ * chore: Better tests * chore: Bump patch version
1 parent 129af20 commit cf8bf5a

File tree

5 files changed

+97
-11
lines changed

5 files changed

+97
-11
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
77

8+
## [3.1.3]
9+
10+
### Added
11+
- Added `debug_mode` configuration option to handle Node.js stdout/stderr messages
12+
- Implemented proper `handle_info/2` callback to handle messages from Node.js processes
13+
- Added safeguards to reset_terminal to prevent errors during termination with invalid ports
14+
15+
### Fixed
16+
- Fixed "unexpected message in handle_info/2" errors when Node.js emits debug messages
17+
- Fixed potential crashes during termination when a port becomes invalid
18+
19+
### Contributors
20+
- @francois-codes for the initial implementation
21+
- Revelry team for refinements
22+
823
## [3.1.2]
924

1025
### Changed

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,22 @@ directory containing your JavaScript modules.
3636
supervisor(NodeJS, [[path: "/node_app_root", pool_size: 4]])
3737
```
3838

39+
### Debug Mode
40+
41+
When working with Node.js applications, you may encounter debug messages or warnings from the Node.js runtime, especially when using inspector or debugging tools. To properly handle these messages:
42+
43+
```elixir
44+
# In your config/dev.exs or other appropriate config file
45+
config :nodejs, debug_mode: true
46+
```
47+
48+
When `debug_mode` is enabled:
49+
- Node.js stdout/stderr messages will be logged at the info level
50+
- Messages like "Debugger listening on..." will not cause errors
51+
- All Node.js processes will log their output through Elixir's Logger
52+
53+
This is particularly useful during development or when debugging Node.js integration issues.
54+
3955
### Calling JavaScript module functions with `NodeJS.call(module, args \\ [])`.
4056

4157
If the module exports a function directly, like this:
@@ -111,4 +127,4 @@ module.exports = async function echo(x, delay = 1000) {
111127
}
112128
```
113129

114-
https://github.com/revelrylabs/elixir-nodejs/blob/master/test/js/slow-async-echo.js
130+
https://github.com/revelrylabs/elixir-nodejs/blob/master/test/js/slow-async-echo.js

lib/nodejs/worker.ex

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,21 +124,28 @@ defmodule NodeJS.Worker do
124124
end
125125
end
126126

127-
defp env do
128-
Mix.env()
129-
rescue
130-
_ -> :release
127+
# Determines if debug mode is enabled via application configuration
128+
defp debug_mode? do
129+
Application.get_env(:nodejs, :debug_mode, false)
131130
end
132131

133-
def handle_info({_pid, data}, state) do
134-
with :dev <- env(),
135-
{_, {:eol, msg}} <- data do
132+
# Handles any messages from the Node.js process
133+
# When debug_mode is enabled, these messages (like Node.js debug info)
134+
# will be logged at info level
135+
@doc false
136+
def handle_info({_pid, {:data, {_flag, msg}}}, state) do
137+
if debug_mode?() do
136138
Logger.info("NodeJS: #{msg}")
137139
end
138140

139141
{:noreply, state}
140142
end
141143

144+
# Catch-all handler for other messages
145+
def handle_info(_message, state) do
146+
{:noreply, state}
147+
end
148+
142149
defp decode(data) do
143150
data
144151
|> to_string()
@@ -149,9 +156,16 @@ defmodule NodeJS.Worker do
149156
end
150157
end
151158

159+
# Safely resets the terminal, handling potential errors if
160+
# the port is already closed or invalid
152161
defp reset_terminal(port) do
153-
Port.command(port, "\x1b[0m\x1b[?7h\x1b[?25h\x1b[H\x1b[2J")
154-
Port.command(port, "\x1b[!p\x1b[?47l")
162+
try do
163+
Port.command(port, "\x1b[0m\x1b[?7h\x1b[?25h\x1b[H\x1b[2J")
164+
Port.command(port, "\x1b[!p\x1b[?47l")
165+
rescue
166+
_ ->
167+
Logger.debug("NodeJS: Could not reset terminal - port may be closed")
168+
end
155169
end
156170

157171
@doc false

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ defmodule NodeJS.MixProject do
44
def project do
55
[
66
app: :nodejs,
7-
version: "3.1.2",
7+
version: "3.1.3",
88
elixir: "~> 1.12",
99
start_permanent: Mix.env() == :prod,
1010
deps: deps(),

test/nodejs_test.exs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,4 +277,45 @@ defmodule NodeJS.Test do
277277
assert Enum.all?(results, &match?({:ok, "clean output"}, &1))
278278
end
279279
end
280+
281+
describe "debug mode" do
282+
test "handles debug messages without crashing" do
283+
File.mkdir_p!("test/js/debug_test")
284+
285+
File.write!("test/js/debug_test/debug_logger.js", """
286+
// This file outputs debugging information to stdout
287+
console.log("Debug message: Module loading");
288+
console.debug("Debug message: Initializing module");
289+
290+
module.exports = function testFunction(input) {
291+
console.log(`Debug message: Function called with input: ${input}`);
292+
console.debug("Debug message: Processing input");
293+
294+
return `Processed: ${input}`;
295+
};
296+
""")
297+
298+
# With debug_mode disabled, function still works despite debug output
299+
result = NodeJS.call("debug_test/debug_logger", ["test input"])
300+
assert {:ok, "Processed: test input"} = result
301+
302+
# Enable debug_mode to verify it works in that mode too
303+
original_setting = Application.get_env(:nodejs, :debug_mode)
304+
Application.put_env(:nodejs, :debug_mode, true)
305+
306+
# Function still works with debug_mode enabled
307+
result = NodeJS.call("debug_test/debug_logger", ["test input"])
308+
assert {:ok, "Processed: test input"} = result
309+
310+
# Restore original setting
311+
if is_nil(original_setting) do
312+
Application.delete_env(:nodejs, :debug_mode)
313+
else
314+
Application.put_env(:nodejs, :debug_mode, original_setting)
315+
end
316+
317+
# Clean up
318+
File.rm!("test/js/debug_test/debug_logger.js")
319+
end
320+
end
280321
end

0 commit comments

Comments
 (0)