-
-
Notifications
You must be signed in to change notification settings - Fork 608
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
221 additions
and
66 deletions.
There are no files selected for viewing
86 changes: 86 additions & 0 deletions
86
fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/WebAPIService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/* | ||
* FXGL - JavaFX Game Library. The MIT License (MIT). | ||
* Copyright (c) AlmasB ([email protected]). | ||
* See LICENSE for details. | ||
*/ | ||
|
||
package com.almasb.fxgl.intelligence | ||
|
||
import com.almasb.fxgl.core.concurrent.Async | ||
import com.almasb.fxgl.logging.Logger | ||
import com.almasb.fxgl.net.ws.LocalWebSocketServer | ||
import com.almasb.fxgl.net.ws.RPCService | ||
import javafx.beans.property.ReadOnlyBooleanProperty | ||
import javafx.beans.property.ReadOnlyBooleanWrapper | ||
import org.openqa.selenium.WebDriver | ||
import org.openqa.selenium.chrome.ChromeDriver | ||
import org.openqa.selenium.chrome.ChromeOptions | ||
|
||
/** | ||
* Provides access to JS-driven implementation. | ||
* | ||
* @author Almas Baim (https://github.com/AlmasB) | ||
*/ | ||
abstract class WebAPIService(server: LocalWebSocketServer, private val apiURL: String) : RPCService(server) { | ||
|
||
private val log = Logger.get(WebAPIService::class.java) | ||
|
||
private val readyProp = ReadOnlyBooleanWrapper(false) | ||
|
||
var isReady: Boolean | ||
get() = readyProp.value | ||
protected set(value) { readyProp.value = value } | ||
|
||
fun readyProperty(): ReadOnlyBooleanProperty { | ||
return readyProp.readOnlyProperty | ||
} | ||
|
||
private var webDriver: WebDriver? = null | ||
|
||
/** | ||
* Starts this service in a background thread. | ||
* Can be called after stop() to restart the service. | ||
* If the service has already started, then calls stop() and restarts it. | ||
*/ | ||
fun start() { | ||
Async.startAsync { | ||
try { | ||
if (webDriver != null) { | ||
stop() | ||
} | ||
|
||
val options = ChromeOptions() | ||
options.addArguments("--headless=new") | ||
options.addArguments("--use-fake-ui-for-media-stream") | ||
|
||
webDriver = ChromeDriver(options) | ||
webDriver!!.get(apiURL) | ||
|
||
onWebDriverLoaded(webDriver!!) | ||
} catch (e: Exception) { | ||
log.warning("Failed to start Chrome web driver. Ensure Chrome is installed in default location") | ||
log.warning("Error data", e) | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Stops this service. | ||
* No-op if it has not started via start() before. | ||
*/ | ||
fun stop() { | ||
try { | ||
if (webDriver != null) { | ||
webDriver!!.quit() | ||
webDriver = null | ||
} | ||
} catch (e: Exception) { | ||
log.warning("Failed to quit web driver", e) | ||
} | ||
} | ||
|
||
/** | ||
* Called after the web driver has loaded the page. | ||
*/ | ||
protected open fun onWebDriverLoaded(webDriver: WebDriver) { } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/net/ws/RPCService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
* FXGL - JavaFX Game Library. The MIT License (MIT). | ||
* Copyright (c) AlmasB ([email protected]). | ||
* See LICENSE for details. | ||
*/ | ||
|
||
package com.almasb.fxgl.net.ws | ||
|
||
import com.almasb.fxgl.core.EngineService | ||
import com.almasb.fxgl.core.reflect.ReflectionFunctionCaller | ||
import com.almasb.fxgl.logging.Logger | ||
|
||
private const val SEPARATOR = "*,,*" | ||
private const val FUNCTION_CALL_TAG = "F_CALL:" | ||
private const val FUNCTION_RETURN_TAG = "F_RETURN:" | ||
|
||
/** | ||
* Allows a remote application (possibly written in a different language) | ||
* to issue function calls to and accept function calls from subclasses of this service. | ||
* | ||
* @author Almas Baim (https://github.com/AlmasB) | ||
*/ | ||
abstract class RPCService( | ||
|
||
/** | ||
* The server to which clients connect. | ||
* Maintenance responsibility of the server object lies with this RPC service. | ||
*/ | ||
protected val server: LocalWebSocketServer | ||
) : EngineService() { | ||
|
||
private val log = Logger.get(RPCService::class.java) | ||
|
||
private val rfc = ReflectionFunctionCaller() | ||
|
||
init { | ||
server.addMessageHandler { message -> | ||
if (message.startsWith(FUNCTION_CALL_TAG)) { | ||
val funcName = message.substringAfter(FUNCTION_CALL_TAG).substringBefore(SEPARATOR) | ||
val args = message.substringAfter(SEPARATOR) | ||
.split(SEPARATOR) | ||
.filter { it.isNotEmpty() } | ||
|
||
rfc.call(funcName, args) | ||
} | ||
|
||
if (message.startsWith(FUNCTION_RETURN_TAG)) { | ||
// TODO: | ||
} | ||
} | ||
} | ||
|
||
override fun onInit() { | ||
rfc.addFunctionCallTarget(this) | ||
log.debug("Added ${javaClass.simpleName} methods: ${rfc.methods.map { it.name }}") | ||
|
||
server.start() | ||
} | ||
|
||
fun rpcRun(funcName: String, vararg args: String) { | ||
rpcRun(funcName, args.toList()) | ||
} | ||
|
||
fun rpcRun(funcName: String, args: List<String>) { | ||
var argsString = "" | ||
|
||
args.forEach { argsString += it + SEPARATOR } | ||
|
||
if (argsString.isNotEmpty()) { | ||
argsString = argsString.removeSuffix(SEPARATOR) | ||
} | ||
|
||
server.send("$FUNCTION_CALL_TAG$funcName$SEPARATOR$argsString") | ||
} | ||
|
||
private fun rpcReturn() { | ||
// TODO: | ||
} | ||
|
||
override fun onExit() { | ||
server.stop() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters