我一直在嘗試創建一個本地進程,它將充當我的服務器的CLI。這個想法類似於Drush對Drupal服務器的做法。在服務器和本地進程之間創建通信流
我還沒有創建CLI界面(可能會使用第三方代碼),但我想分享我的解決方案,以解決我在此問題上遇到的最大障礙:將本地進程之間的消息傳輸到正在運行的活動服務器使用REST服務是因爲它們會增加一些命令的安全風險。
我一直在嘗試創建一個本地進程,它將充當我的服務器的CLI。這個想法類似於Drush對Drupal服務器的做法。在服務器和本地進程之間創建通信流
我還沒有創建CLI界面(可能會使用第三方代碼),但我想分享我的解決方案,以解決我在此問題上遇到的最大障礙:將本地進程之間的消息傳輸到正在運行的活動服務器使用REST服務是因爲它們會增加一些命令的安全風險。
注:此代碼是寫在Scala,但可以轉換爲Java
首先我們需要創建一個擴展HttpServlet的一個servlet類。對於每個GET請求,servlet類將檢查我們的線程(稍後解釋)是否已打開,如果未嘗試啓動它。請注意,我們在啓動方法中使用try catch,因爲如果線程的狀態爲TERMINATED isAlive將返回true(我不知道爲什麼)。
我還實施了destroy方法來殺死我們的線程,如果servlet死亡。我不知道會發生什麼,如果該servlet死正在運行的線程,但以防萬一...
Servlet.scala:
package com.example
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class Servlet extends HttpServlet {
override def doGet(req: HttpServletRequest, resp: HttpServletResponse) = {
if (!CLIThread.isAlive) {
try {
CLIThread.start
}
catch {
case _ => resp.getOutputStream().println("Error: thread state is, " + CLIThread.getState)
}
}
resp.getOutputStream().println(CLIThread.pool)
}
override def destroy(): Unit = {
super.destroy()
CLIThread.shutdown
}
}
我們的線程(CLIThread)是scala object擴展Thread類。
CLIThread有2種方法,池&關閉,並且它們都被傳遞給我們的Runnable實現。
CLIRunnable是傳遞給線程構造函數的Runnable實現對象。 (),一個true布爾值(keepAlive)和一個空字符串(_pool)作爲變量。默認情況下,CLIRunnable有一個空ServerSocket(偵聽器),Socket(套接字)&。
run方法:
池方法:
關機方法:
CLIThread.scala
package com.example
import java.io.InputStream
import java.net.ServerSocket
import java.net.Socket
object CLIThread extends Thread(CLIRunner) {
def pool: String = CLIRunner.pool
def shutdown() = CLIRunner.shutdown()
}
protected final object CLIRunner extends Runnable {
var listener: ServerSocket = null
var socket: Socket = null
var in: InputStream = null
private var keepAlive = true
private var _pool = ""
def run: Unit = {
var ok = false
while (!ok) {
try {
listener = new ServerSocket((math.random * 10000).toInt)
ok = true;
}
catch {
case _ => {}
}
}
socket = listener.accept()
in = socket.getInputStream
while (keepAlive) {
while (in.available() > 0) _pool += in.read().toChar
}
}
def pool: String = if (in != null) {
val temp = _pool
_pool = ""
return temp
}
else if (listener != null) (listener.getInetAddress, listener.getLocalPort).toString
else "listener == null..."
def shutdown() {
keepAlive = false
if (listener != null) {
if (socket == null)
(new Socket(listener.getInetAddress, listener.getLocalPort)).close()
if (socket != null)
socket.close()
listener.close()
}
}
}
CLI.scala
package com.example
import java.net.Socket
import java.net.URL
object CLI extends App {
val addr = args(0) // The server address (example.com:8080)
val addrUrl = new URL("http://" + addr + "/~cli/addr")
var con = addrUrl.openConnection()
var in = con.getInputStream()
var cliAddr = ""
while (in.available() > 0)
cliAddr += in.read.toChar
val portUrl = new URL("http://" + addr + "/~cli/port")
con = portUrl.openConnection()
in = con.getInputStream()
var cliPort = ""
while (in.available() > 0)
cliPort += in.read.toChar
val socket = new Socket(cliAddr, Integer.valueOf(cliPort))
implicit def stringToByteArray(s: String) = s.toCharArray.map(c => c.toByte)
socket.getOutputStream().write("Hellllo from CLI process")
}
CliAddr.scala
package org.sdms
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class CliAddr extends HttpServlet {
override def doGet(req: HttpServletRequest, resp: HttpServletResponse) {
resp.getWriter.print(CLIRunner.listener.getInetAddress.getHostAddress)
}
}
CliPort.scala
package com.example
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class CliPort extends HttpServlet {
override def doGet(req: HttpServletRequest, resp: HttpServletResponse) {
resp.getWriter.print(CLIRunner.listener.getLocalPort)
}
}