Copilot commented on code in PR #2869:
URL: https://github.com/apache/groovy/pull/2869#discussion_r3930186680
##########
src/spec/doc/tools-groovy.adoc:
##########
@@ -54,14 +54,29 @@ int (disable any int based optimizations) |
| -e <script> | | specify an inline command line script | groovy -e "println
new Date()"
| -h | --help | Displays usage information for the command line groovy command
| groovy --help
| -i <extension> | | modify files in place; create backup if extension is
given (e.g. '.bak') |
-| -l <port> | | listen on a port and process inbound lines (default: 1960) |
+| -l <[host:]port> | | listen on a port and process inbound lines (default:
1960); binds the loopback address unless a host is given | groovy -l
0.0.0.0:1960 -e "line.reverse()"
| -n | | process files line by line using implicit 'line' variable |
| -p | | process files line by line and print result (see also -n) |
| -v | --version | display the Groovy and JVM versions | groovy -v
| -pa | --parameters | Generates metadata for reflection on method parameter
names on JDK 8 and above. Defaults to false. | groovy --parameters Person.groovy
| -pr | --enable-preview | Enable preview Java features (jdk12+ only). |
groovy --enable-preview Person.groovy
|=======================================================================
+The `-l` option is a developer convenience for experimenting with a line-driven
+script, in the same spirit as `groovysh` but reading from a socket instead of a
+terminal. It is not an application server.
+
+It runs the given script once for every line a client sends, with the
+line available as the implicit `line` variable and the connection as `out` and
+`socket`. The listening socket is bound to the loopback address, so only
clients on
+the same machine can connect. Supply a host to listen more widely --
`0.0.0.0:1960`
+for every interface, or a single address to pick one. The script is re-read
for each
+connection, so editing it takes effect without a restart.
Review Comment:
This hot-reload claim does not match the implementation. `getScriptSource`
constructs one `GroovyCodeSource`, whose file/URL constructors eagerly capture
`scriptText`, and each loop iteration recompiles that same captured text;
editing the file therefore has no effect until the listener is restarted.
##########
src/main/java/groovy/ui/GroovySocketServer.java:
##########
@@ -129,29 +135,59 @@ private static synchronized String generateScriptName() {
* @param autoOutput
* whether output should be automatically echoed back to the client
* @param port
- * the port to listen on
+ * the port to listen on, bound to the loopback address
* @since 2.3.0
*/
public GroovySocketServer(GroovyShell groovy, GroovyCodeSource source,
boolean autoOutput, int port) {
+ this(groovy, source, autoOutput, new
InetSocketAddress(InetAddress.getLoopbackAddress(), port));
+ }
+
+ /**
+ * This creates and starts the socket server on a new Thread. There is no
need to call run or spawn
+ * a new thread yourself.
+ * <p>
+ * Binding to anything other than a loopback address accepts connections
from other hosts. The
+ * script is run once per line received, and this class performs no
authentication, so the port
+ * should be reachable only by peers the script is prepared to serve.
+ * @param groovy
+ * The GroovyShell object that evaluates the incoming text. If you
need additional classes in the
+ * classloader then configure that through this object.
+ * @param source
+ * GroovyCodeSource for the Groovy script
+ * @param autoOutput
+ * whether output should be automatically echoed back to the client
+ * @param bindAddress
+ * the address and port to listen on
+ * @since 6.0.0
+ */
+ public GroovySocketServer(GroovyShell groovy, GroovyCodeSource source,
boolean autoOutput, InetSocketAddress bindAddress) {
this.groovy = groovy;
this.source = source;
this.autoOutput = autoOutput;
- try {
- url = new URI("http", null,
InetAddress.getLocalHost().getHostAddress(), port, "/", null, null).toURL();
- System.out.println("groovy is listening on port " + port);
- } catch (IOException | URISyntaxException e) {
- e.printStackTrace();
+ if (bindAddress.isUnresolved()) {
+ throw new IllegalArgumentException("Cannot listen on unresolved
address: " + bindAddress);
+ }
+ this.bindAddress = bindAddress;
+ System.out.println("groovy is listening on " + describe(bindAddress));
Review Comment:
The banner is emitted before the `ServerSocket` is created, so it can claim
the server is listening even when the bind later fails. It also formats the
requested address: for the valid port `0`, Java assigns an ephemeral port but
this prints `port 0`, leaving users without the actual endpoint. Emit the
banner only after a successful bind and derive it from
`getLocalSocketAddress()`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]