All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.isyscore.cse.sdk.ISCCrossScriptEngine.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0
Show newest version
package com.isyscore.cse.sdk

import com.isyscore.kotlin.common.*
import org.slf4j.LoggerFactory
import java.io.File
import java.util.logging.Logger
import kotlin.math.log

data class ExecParam(
    val paramName: String,
    val paramType: String,
    val paramValue: String = "")
private data class InternalCompileParam(val code: String, val outputPath: String, val params: List)
private data class InternalExecuteParam(val data: List)
private data class ParamDTO(
    val binaryPath: String,
    val timeout: Long = 0L,
    val isTest: Boolean = false,
    val params: List
)
data class CompileResult(val code: Int, val message: String, val codeId: String)
data class ExecOutput(val output: String, val error: String)
data class ExecuteResult(val code: Int, val message: String, val data: ExecOutput)

/**
 * 指令集 Cross Script 引擎总控
 *
 * 需要在目标机器上安装 Cross Script 必备文件:
 *
 * **linux**:
 *
 *    libcrossscript.so,置于 /usr/lib/ 内
 *
 *    iscx,置于 /usr/bin/ 内
 *
 * **MacOS**
 *
 *    libcrossscript.dylib,置于 /usr/local/lib/ 内
 *
 *    iscx,置于 /usr/local/bin/ 内
 *
 * **Windows (仅x86_64)**
 *
 *    crossscript.dll,置于 C:\Window\system32\ 内
 *
 *    iscx.exe,置于 C:\Window\system32\ 内
 *
 * 特别说明,已支持 Apple M1 芯片
 */
object ISCCrossScriptEngine {

    @JvmStatic val VERSION = 100

    val logger = LoggerFactory.getLogger(ISCCrossScriptEngine::class.java)

    private val SPL = if (isWindows) "\\" else "/"
    private val EXEC = when {
        isWindows -> "C:\\Window\\System32\\iscx.exe"
        isMac -> "/usr/local/bin/iscx"
        else -> "/usr/bin/iscx"
    }
    private val COMP_EXEC = when {
        isWindows -> "C:\\Window\\System32\\isccx.exe"
        isMac -> "/usr/local/bin/isccx"
        else -> "/usr/bin/isccx"
    }

    /**
     * 定义参数类型:int
     */
    @JvmStatic val TYPE_INT = "01"

    /**
     * 定义参数类型: long
     */
    @JvmStatic val TYPE_INT64 = "02"

    /**
     * 定义参数类型: float
     */
    @JvmStatic val TYPE_FLOAT = "03"

    /**
     * 定义参数类型: double
     */
    @JvmStatic val TYPE_DOUBLE = "04"

    /**
     * 定义参数类型: boolean
     */
    @JvmStatic val TYPE_BOOL = "05"

    /**
     * 定义参数类型: string
     */
    @JvmStatic val TYPE_STRING = "06"

    init {
        try {
            System.loadLibrary("crossscript")
            println("load crossscript finished")
        } catch (th: Throwable) {
            println("load crossscript error: $th")
        }
    }

    private external fun execute(timeout: Long, codeId: String, params: String): String
    private external fun version(): String

    /**
     * 环境检查,建议在脚本执行前,进行环境检查,以便了解部署是否有不完善之处
     *
     * 更为合理的操作是,在程序启动时,执行一次检查,后续即可不必再进行检查
     *
     * 当检查出有问题的项目时,将以日志形式输出到 Terminal
     */
    @JvmStatic
    fun environmentCheck(): Boolean {
        var ret = true
        if (!File(EXEC).exists()) {
            logger.error("$EXEC 未正确安装")
            ret = false
        } else {
            val vE = runCommand {
                commands.add(EXEC)
                commands.add("version")
            }.output.trim().toIntOrNull()
            if (vE == null) {
                logger.error("$EXEC 太旧,不支持版本检查")
                ret = false
            } else {
                if (vE != VERSION) {
                    logger.error("$EXEC 版本号为 $vE,与当前环境要求不符")
                    ret = false
                }
            }
        }
        if (!File(COMP_EXEC).exists()) {
            logger.error("$COMP_EXEC 未正确安装")
            ret = false
        } else {
            val vE = runCommand {
                commands.add(COMP_EXEC)
                commands.add("version")
            }.output.trim().toIntOrNull()
            if (vE == null) {
                logger.error("$COMP_EXEC 太旧,不支持版本检查")
                ret = false
            } else {
                if (vE != VERSION) {
                    logger.error("$COMP_EXEC 版本号为 $vE,与当前环境要求不符")
                    ret = false
                }
            }
        }

        val vLib = try {
            version().toIntOrNull()
        } catch (th: Throwable) {
            null
        }

        if (vLib == null) {
            logger.error("共享库太旧,不支持版本检查")
            ret = false
        } else {
            if (vLib != VERSION) {
                logger.error("共享库版本号为 $vLib,与当前环境要求不符")
                ret = false
            }
        }
        return ret
    }

    /**
     * 编译 Cross Script 脚本代码
     *
     * @param code 要编译的脚本代码(推荐使用强类型语言,指令集内部项目建议 typejs)
     * @param params 参数列表,仅需要填入参数名称和类型
     * @return 编译结果
     *
     * @see TYPE_INT
     * @see TYPE_INT64
     * @see TYPE_FLOAT
     * @see TYPE_DOUBLE
     * @see TYPE_BOOL
     * @see TYPE_STRING
     *
     * @see CompileResult
     */
    @JvmStatic
    fun compile(code: String, params: List): CompileResult {
        val path = "." + SPL + "scripts" + SPL
        val pjson = InternalCompileParam(
            code = code,
            outputPath = path,
            params = params).toJson()
        return runCommand {
            commands.add(COMP_EXEC)
            commands.add(pjson)
        }.output.toObj()
    }

    /**
     * 执行 Cross Script 的二进制程序
     *
     * 需要注意,执行此方法时,若产生了内存异常,将引起 Java 进程崩溃,需要在测试执行后才使用此方法来高速执行脚本
     *
     * @param timeout 执行超时时间,单位毫秒,设置为 0 时不使用超时限制
     * @param codeId 二进制程序 ID
     * @param params 参数列表
     * @return 执行结果
     *
     * @see TYPE_INT
     * @see TYPE_INT64
     * @see TYPE_FLOAT
     * @see TYPE_DOUBLE
     * @see TYPE_BOOL
     * @see TYPE_STRING
     *
     * @see ExecuteResult
     */
    @JvmStatic
    fun execute(timeout: Long, codeId: String, params: List): ExecuteResult {
        val pjson = InternalExecuteParam(params).toJson()
        return try {
            execute(timeout, codeId, pjson).toObj()
        } catch (e: Throwable) {
            ExecuteResult(500, e.message ?: "unknown", ExecOutput("", ""))
        }
    }

    /**
     * 尝试执行 Cross Script 的二进制脚本
     *
     * 注意,这个方法用于对脚本的运行情况进行试验,性能较差,但是产生异常时不会引起 Java 进程崩溃。在正式执行前,应当用此方法进行试验
     *
     * @param timeout 执行超时时间,单位毫秒,设置为 0 时不使用超时限制
     * @param codeId 二进制程序 ID
     * @param params 参数列表
     * @return 执行结果
     *
     * @see TYPE_INT
     * @see TYPE_INT64
     * @see TYPE_FLOAT
     * @see TYPE_DOUBLE
     * @see TYPE_BOOL
     * @see TYPE_STRING
     *
     * @see ExecuteResult
     */
    @JvmStatic
    fun testExecute(timeout: Long, codeId: String, params: List): ExecuteResult {
        val path = "." + SPL + "scripts" + SPL + codeId
        if (!File(path).exists()) {
            return ExecuteResult(400, "文件不存在", ExecOutput("", ""))
        }
        val pJson = ParamDTO(path, timeout, true, params).toJson()
        return runCommand {
            commands.add(EXEC)
            commands.add(pJson)
        }.output.toObj()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy