简体   繁体   中英

Is there an equivalent to Python yield's behavior in Groovy?

Trying to learn Groovy, and it's been a fun and only slightly confusing adventure so far. What I'm currently trying to do is stand up a server, make a wget request to it and when that request is received, have a certain action be executed - in this case, just creating a new file:

import java.net.http.HttpResponse

class ServerLogic {
    static def holdupServer() {
        println('Standing up server..\n')
        def socketServer = new ServerSocket(5000)
        // server is up
        socketServer.accept { socket ->
        // the lines below only execute when a connection is made to the server
        socket.withStreams { input, output ->
            println("[${new Date()}] HELLO\n")
            def newFile = new File("/home/nick/IdeaProjects/groovy_learning/resources/new.txt")
            newFile.createNewFile()
            newFile.text = 'Hello!!!'
            println("NEW FILE SHOULD HAVE BEEN CREATED.")
            println ">> READ: ${input.newReader().readLine()}"
        }
    }
        return HttpResponse
    }

}

ServerLogic.holdupServer()

With the above code, when I execute a wget http://localhost:5000 , it "works" in the sense that the file is created like I want it to be, but the wget output is unhappy:

--2021-07-17 15:42:32--  http://localhost:5000/
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:5000... connected.
HTTP request sent, awaiting response... No data received.
Retrying.

--2021-07-17 15:42:33--  (try: 2)  http://localhost:5000/
Connecting to localhost (localhost)|127.0.0.1|:5000... failed: Connection refused.
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:5000... failed: Connection refused.  
// these occur because the server has shut down after the last println call, when the `return HttpResponse` triggers

So from that, we can reason out that there isn't a proper response being returned, even though I have the return HttpResponse after the sockerServer.accept ... logic. My thought on how to solve the problem (primarily because I come from a Python background) would be to somehow mimic yield ing a response in Python (basically, return a response without breaking out of the holdupServer() logic and thus breaking the server connection). Is there a way to achieve this in Groovy, or is there a different approach I could use to essentially return a valid HttpResponse without exiting the holdupServer() block?

Explanation

You can use a function callback , which in Groovy translates to a closure callback. Basically, you pass the value you want to return to another function/method defering the stack on the current method. This approach works essentially on all languages. In java (the versions which don't support lambda), for instance, you would have to pass an object in which you would call a method later.

Example

import java.net.http.HttpResponse

class ServerLogic {
    static def holdupServer(Closure closure) {
        (0..2).each {
            closure.call(HttpResponse)
        }
    }
}

ServerLogic.holdupServer { httpResponse ->
    println httpResponse
}

Output

interface java.net.http.HttpResponse
interface java.net.http.HttpResponse
interface java.net.http.HttpResponse

Addressing OP's comment

You have to provide some headers. At least Content-Type and Content-Length should've been provided along with the data and HTTP status (HTTP/1.1 200, in this case) properly formatted. Also, you should've wrapped the ServerSocket.accept calls in a while loop.

See the MDN Overview on HTTP .

Code

class ServerLogic {
    static HEADERS = [
      "HTTP/1.1 200",
      "Content-Type: text/html; charset=utf-8",
      "Connection: Keep-Alive",
      "Keep-Alive: timeout=5, max=1000",
      "Content-Length: %d\r\n",
      "%s"
    ].join("\r\n")

    static def holdupServer(Closure callback) {
      println('Standing up server..\n')
      def socketServer = new ServerSocket(5000)
        // server is up
      while(true) { // Continue to accept connections
        socketServer.accept { socket ->
        // the lines below only execute when a connection is made to the server
          callback.call(socket) // call function
      }
    }
  }
}

ServerLogic.holdupServer { Socket socket ->
  String data = "RESPONSE <--\n"
  def response = String.format(ServerLogic.HEADERS, data.size(), data)
  println response
  socket << response
}

Client output

RESPONSE <--

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM