Scheduler JavaFX and Swing now have Future
This commit is contained in:
@@ -30,7 +30,7 @@ private class CoupleTask<P: Task>(private val pred: P, private val succ: Task.(P
|
||||
}
|
||||
}
|
||||
|
||||
infix fun <T: Task> T.then(b: Task): Task = CoupleTask(this, { b }, true)
|
||||
infix fun Task.then(b: Task): Task = CoupleTask(this, { b }, true)
|
||||
|
||||
/**
|
||||
* @param b A runnable that decides what to do next, You can also do something here.
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.net.URL
|
||||
import java.math.BigInteger
|
||||
import java.util.logging.Level
|
||||
|
||||
class FileDownloadTask(val url: URL, val file: File, val hash: String? = null, val retry: Int = 5, val proxy: Proxy = Proxy.NO_PROXY): Task() {
|
||||
class FileDownloadTask @JvmOverloads constructor(val url: URL, val file: File, val hash: String? = null, val retry: Int = 5, val proxy: Proxy = Proxy.NO_PROXY): Task() {
|
||||
override val scheduler: Scheduler = Scheduler.IO_THREAD
|
||||
|
||||
var onFailed = EventManager<FailedEvent<URL>>()
|
||||
|
||||
@@ -25,7 +25,7 @@ import java.net.Proxy
|
||||
import java.net.URL
|
||||
import java.nio.charset.Charset
|
||||
|
||||
class GetTask(val url: URL, val encoding: Charset = Charsets.UTF_8, private val retry: Int = 5, private val proxy: Proxy = Proxy.NO_PROXY): TaskResult<String>() {
|
||||
class GetTask @JvmOverloads constructor(val url: URL, val encoding: Charset = Charsets.UTF_8, private val retry: Int = 5, private val proxy: Proxy = Proxy.NO_PROXY): TaskResult<String>() {
|
||||
override val scheduler: Scheduler = Scheduler.IO_THREAD
|
||||
|
||||
override fun execute() {
|
||||
|
||||
@@ -18,38 +18,51 @@
|
||||
package org.jackhuang.hmcl.task
|
||||
|
||||
import javafx.application.Platform
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.Future
|
||||
import java.util.concurrent.*
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import javax.swing.SwingUtilities
|
||||
|
||||
interface Scheduler {
|
||||
fun schedule(block: Runnable): Future<*>?
|
||||
fun schedule(block: Callable<Unit>): Future<*>?
|
||||
|
||||
companion object Schedulers {
|
||||
val IMMEDIATE = object : Scheduler {
|
||||
override fun schedule(block: Runnable): Future<*>? {
|
||||
block.run()
|
||||
return null
|
||||
}
|
||||
}
|
||||
val JAVAFX: Scheduler = object : Scheduler {
|
||||
override fun schedule(block: Runnable): Future<*>? {
|
||||
Platform.runLater(block)
|
||||
return null
|
||||
}
|
||||
}
|
||||
val SWING: Scheduler = object : Scheduler {
|
||||
override fun schedule(block: Runnable): Future<*>? {
|
||||
SwingUtilities.invokeLater(block)
|
||||
return null
|
||||
val JAVAFX: Scheduler = SchedulerImpl(Platform::runLater)
|
||||
val SWING: Scheduler = SchedulerImpl(SwingUtilities::invokeLater)
|
||||
private class SchedulerImpl(val executor: (() -> Unit) -> Unit) : Scheduler {
|
||||
override fun schedule(block: Callable<Unit>): Future<*>? {
|
||||
val latch = CountDownLatch(1)
|
||||
val wrapper = AtomicReference<Exception>()
|
||||
executor {
|
||||
try {
|
||||
block.call()
|
||||
} catch (e: Exception) {
|
||||
wrapper.set(e)
|
||||
} finally {
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
return object : Future<Unit> {
|
||||
override fun get(timeout: Long, unit: TimeUnit) {
|
||||
latch.await(timeout, unit)
|
||||
val e = wrapper.get()
|
||||
if (e != null) throw ExecutionException(e)
|
||||
}
|
||||
override fun get() {
|
||||
latch.await()
|
||||
val e = wrapper.get()
|
||||
if (e != null) throw ExecutionException(e)
|
||||
}
|
||||
override fun isDone() = latch.count == 0L
|
||||
override fun isCancelled() = false
|
||||
override fun cancel(mayInterruptIfRunning: Boolean) = false
|
||||
}
|
||||
}
|
||||
}
|
||||
val NEW_THREAD: Scheduler = object : Scheduler {
|
||||
override fun schedule(block: Runnable) = CACHED_EXECUTOR.submit(block)
|
||||
override fun schedule(block: Callable<Unit>) = CACHED_EXECUTOR.submit(block)
|
||||
}
|
||||
val IO_THREAD: Scheduler = object : Scheduler {
|
||||
override fun schedule(block: Runnable) = IO_EXECUTOR.submit(block)
|
||||
override fun schedule(block: Callable<Unit>) = IO_EXECUTOR.submit(block)
|
||||
}
|
||||
val DEFAULT = NEW_THREAD
|
||||
private val CACHED_EXECUTOR: ExecutorService by lazy {
|
||||
@@ -57,11 +70,11 @@ interface Scheduler {
|
||||
}
|
||||
|
||||
private val IO_EXECUTOR: ExecutorService by lazy {
|
||||
Executors.newFixedThreadPool(6, { r: Runnable ->
|
||||
Executors.newFixedThreadPool(6) { r: Runnable ->
|
||||
val thread: Thread = Executors.defaultThreadFactory().newThread(r)
|
||||
thread.isDaemon = true
|
||||
thread
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun shutdown() {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.task
|
||||
|
||||
internal class SimpleTask(private val runnable: () -> Unit, override val scheduler: Scheduler = Scheduler.DEFAULT) : Task() {
|
||||
internal class SimpleTask @JvmOverloads constructor(private val runnable: () -> Unit, override val scheduler: Scheduler = Scheduler.DEFAULT) : Task() {
|
||||
override fun execute() {
|
||||
runnable()
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.task
|
||||
|
||||
import javafx.beans.property.ReadOnlyDoubleProperty
|
||||
import javafx.beans.property.ReadOnlyDoubleWrapper
|
||||
import javafx.beans.property.ReadOnlyStringProperty
|
||||
import javafx.beans.property.ReadOnlyStringWrapper
|
||||
import org.jackhuang.hmcl.event.EventManager
|
||||
import org.jackhuang.hmcl.util.*
|
||||
@@ -69,19 +71,23 @@ abstract class Task {
|
||||
protected open val progressInterval = 1000L
|
||||
private var lastTime = Long.MIN_VALUE
|
||||
private val progressUpdate = AtomicReference<Double>()
|
||||
val progressProperty = ReadOnlyDoubleWrapper(this, "progress", 0.0)
|
||||
private val progressPropertyImpl = ReadOnlyDoubleWrapper(this, "progress", 0.0)
|
||||
val progressProperty: ReadOnlyDoubleProperty = progressPropertyImpl.readOnlyProperty
|
||||
@JvmName("progressProperty") get
|
||||
protected fun updateProgress(progress: Int, total: Int) = updateProgress(1.0 * progress / total)
|
||||
protected fun updateProgress(progress: Double) {
|
||||
val now = System.currentTimeMillis()
|
||||
if (now - lastTime >= progressInterval) {
|
||||
progressProperty.updateAsync(progress, progressUpdate)
|
||||
progressPropertyImpl.updateAsync(progress, progressUpdate)
|
||||
lastTime = now
|
||||
}
|
||||
}
|
||||
|
||||
private val messageUpdate = AtomicReference<String>()
|
||||
val messageProperty = ReadOnlyStringWrapper(this, "message", null)
|
||||
protected fun updateMessage(newMessage: String) = messageProperty.updateAsync(newMessage, messageUpdate)
|
||||
private val messagePropertyImpl = ReadOnlyStringWrapper(this, "message", null)
|
||||
val messageProperty: ReadOnlyStringProperty = messagePropertyImpl.readOnlyProperty
|
||||
@JvmName("messageProperty") get
|
||||
protected fun updateMessage(newMessage: String) = messagePropertyImpl.updateAsync(newMessage, messageUpdate)
|
||||
|
||||
val onDone = EventManager<TaskEvent>()
|
||||
|
||||
@@ -97,11 +103,11 @@ abstract class Task {
|
||||
}
|
||||
|
||||
private val subTaskRunnable = { task: Task ->
|
||||
this.messageProperty.bind(task.messageProperty)
|
||||
this.progressProperty.bind(task.progressProperty)
|
||||
this.messagePropertyImpl.bind(task.messagePropertyImpl)
|
||||
this.progressPropertyImpl.bind(task.progressPropertyImpl)
|
||||
task.run()
|
||||
this.messageProperty.unbind()
|
||||
this.progressProperty.unbind()
|
||||
this.messagePropertyImpl.unbind()
|
||||
this.progressPropertyImpl.unbind()
|
||||
}
|
||||
|
||||
fun executor() = TaskExecutor().submit(this)
|
||||
|
||||
@@ -52,7 +52,7 @@ class TaskExecutor() {
|
||||
while (!taskQueue.isEmpty() && !canceled) {
|
||||
val task = taskQueue.poll()
|
||||
if (task != null) {
|
||||
val future = task.scheduler.schedule(Runnable { executeTask(task) })
|
||||
val future = task.scheduler.schedule(Callable { executeTask(task); Unit })
|
||||
try {
|
||||
future?.get()
|
||||
} catch (e: InterruptedException) {
|
||||
@@ -142,8 +142,8 @@ class TaskExecutor() {
|
||||
return flag
|
||||
}
|
||||
|
||||
private inner class Invoker(val task: Task, val latch: CountDownLatch, val boolean: AtomicBoolean): Runnable {
|
||||
override fun run() {
|
||||
private inner class Invoker(val task: Task, val latch: CountDownLatch, val boolean: AtomicBoolean): Callable<Unit> {
|
||||
override fun call() {
|
||||
try {
|
||||
Thread.currentThread().name = task.title
|
||||
if (!executeTask(task))
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
@file:JvmName("Constants")
|
||||
package org.jackhuang.hmcl.util
|
||||
|
||||
import javafx.application.Platform
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
@file:JvmName("HMCLog")
|
||||
package org.jackhuang.hmcl.util
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.lang.reflect.Method
|
||||
import java.security.PrivilegedExceptionAction
|
||||
import java.security.AccessController
|
||||
|
||||
|
||||
object ReflectionHelper {
|
||||
|
||||
private lateinit var unsafe: Unsafe
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.util.logging.Level
|
||||
|
||||
internal class StreamPump(
|
||||
internal class StreamPump @JvmOverloads constructor(
|
||||
val inputStream: InputStream,
|
||||
val callback: (String) -> Unit = {}
|
||||
) : Runnable {
|
||||
|
||||
@@ -23,13 +23,6 @@ import java.io.IOException
|
||||
import java.util.zip.ZipOutputStream
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun zip(src: String, destZip: String) {
|
||||
zip(File(src), File(destZip), null)
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能:把 src 目录下的所有文件进行 zip 格式的压缩,保存为指定 zip 文件
|
||||
|
||||
@@ -43,8 +36,9 @@ fun zip(src: String, destZip: String) {
|
||||
* *
|
||||
* @throws java.io.IOException 压缩失败或无法读取
|
||||
*/
|
||||
@JvmOverloads
|
||||
@Throws(IOException::class)
|
||||
fun zip(src: File, destZip: File, pathNameCallback: ((String, Boolean) -> String?)?) {
|
||||
fun zip(src: File, destZip: File, pathNameCallback: ((String, Boolean) -> String?)? = null) {
|
||||
ZipOutputStream(destZip.outputStream()).use { zos ->
|
||||
val basePath: String
|
||||
if (src.isDirectory)
|
||||
@@ -103,11 +97,6 @@ private fun zipFile(src: File,
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun unzip(zip: File, dest: File) {
|
||||
unzip(zip, dest, null, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文件压缩成zip文件
|
||||
|
||||
@@ -121,8 +110,9 @@ fun unzip(zip: File, dest: File) {
|
||||
* *
|
||||
* @throws java.io.IOException 解压失败或无法写入
|
||||
*/
|
||||
@JvmOverloads
|
||||
@Throws(IOException::class)
|
||||
fun unzip(zip: File, dest: File, callback: ((String) -> Boolean)?, ignoreExistsFile: Boolean) {
|
||||
fun unzip(zip: File, dest: File, callback: ((String) -> Boolean)? = null, ignoreExistsFile: Boolean = true) {
|
||||
val buf = ByteArray(1024)
|
||||
dest.mkdirs()
|
||||
ZipInputStream(zip.inputStream()).use { zipFile ->
|
||||
|
||||
Reference in New Issue
Block a user