Skip to content

Commit

Permalink
Open streamer of StreamableOpenCvPipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
serivesmejia committed Nov 4, 2024
1 parent 4e372c6 commit 15e7f07
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ package com.github.serivesmejia.eocvsim.gui.dialog
import com.github.serivesmejia.eocvsim.EOCVSim
import com.github.serivesmejia.eocvsim.gui.dialog.component.BottomButtonsPanel
import com.github.serivesmejia.eocvsim.gui.dialog.component.OutputPanel
import com.github.serivesmejia.eocvsim.util.loggerForThis
import io.github.deltacv.eocvsim.plugin.loader.PluginManager
import io.github.deltacv.eocvsim.plugin.loader.PluginSource
import io.github.deltacv.eocvsim.plugin.repository.PluginRepositoryManager
Expand Down Expand Up @@ -122,6 +123,8 @@ class PluginOutput(

private val mavenOutputPanel = OutputPanel(mavenBottomButtonsPanel)

private val logger by loggerForThis()

init {
output.isModal = true
output.isAlwaysOnTop = true
Expand Down Expand Up @@ -466,6 +469,8 @@ class PluginOutput(
}

tabbedPane.setComponentAt(0, makePluginManagerPanel())
logger.info("Displaying plugin manager dialog")

output.isVisible = true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ public static long getMemoryUsageMB() {
return (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / MB;
}

public static String loadResStr(String path) throws UnsupportedEncodingException {
return loadIsStr(SysUtil.class.getResourceAsStream(path), Charset.defaultCharset());
}

public static String loadIsStr(InputStream is, Charset charset) throws UnsupportedEncodingException {
return new BufferedReader(new InputStreamReader(is, String.valueOf(charset)))
.lines().collect(Collectors.joining("\n"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@ import java.nio.channels.FileLock
*/
class LockFile(pathname: String) : File(pathname) {

private val raf by lazy { RandomAccessFile(this, "rw") }
companion object {
val POR_UNA_NOCHE = try {
SysUtil.loadResStr("/.lock")
} catch(ex: Exception) {
"lock"
}
}

private var raf = RandomAccessFile(this, "rw")

var lock: FileLock? = null
private set
Expand All @@ -30,12 +38,14 @@ class LockFile(pathname: String) : File(pathname) {
true
}

constructor(file: File) : this(file.absolutePath)

init {
if(isDirectory)
throw IllegalArgumentException("Lock file cannot be a directory")

if(!exists())
SysUtil.saveFileStr(this, "")
SysUtil.saveFileStr(this, POR_UNA_NOCHE)
}

/**
Expand All @@ -44,6 +54,8 @@ class LockFile(pathname: String) : File(pathname) {
* @return true if the file was locked, false otherwise
*/
fun tryLock(log: Boolean = true): Boolean {
raf = RandomAccessFile(this, "rw")

return try {
lock = raf.channel.tryLock()
if(log) logger.trace("Probably locked file $absolutePath")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ class PluginManager(val eocvSim: EOCVSim) {
appender.append(PluginOutput.SPECIAL_FREE)
}

appender.appendln(PluginOutput.SPECIAL_SILENT + "Initializing PluginManager")

superAccessDaemonClient.init()

repositoryManager.init()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ package io.github.deltacv.eocvsim.plugin.security
import com.github.serivesmejia.eocvsim.util.SysUtil
import com.github.serivesmejia.eocvsim.util.loggerForThis
import com.github.serivesmejia.eocvsim.util.extension.plus
import com.github.serivesmejia.eocvsim.util.io.LockFile
import com.github.serivesmejia.eocvsim.util.io.lockDirectory
import com.moandjiezana.toml.Toml
import io.github.deltacv.eocvsim.plugin.loader.PluginManager
import java.io.File
Expand Down Expand Up @@ -58,6 +60,9 @@ object AuthorityFetcher {
const val AUTHORITY_SERVER_URL = "https://raw.githubusercontent.com/deltacv/Authorities/refs/heads/master"

private val AUTHORITIES_FILE = PluginManager.PLUGIN_CACHING_FOLDER + File.separator + "authorities.toml"
private val AUTHORITIES_LOCK_FILE = LockFile(PluginManager.PLUGIN_CACHING_FOLDER + File.separator + "authorities.lock")

private val AUTHORITIES_LOCK_FILE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(3)

private val TTL_DURATION_MS = TimeUnit.HOURS.toMillis(8)

Expand All @@ -74,7 +79,7 @@ object AuthorityFetcher {
}

// Load authorities from file if it exists
if (AUTHORITIES_FILE.exists()) {
if (AUTHORITIES_FILE.exists() && tryLockAuthoritiesFile()) {
try {
val authoritiesToml = Toml().read(AUTHORITIES_FILE)
val authorityData = authoritiesToml.getTable(name)
Expand All @@ -96,6 +101,8 @@ object AuthorityFetcher {
}
}

AUTHORITIES_LOCK_FILE.unlock()

// Fetch the authority from the server
val authorityUrl = "${AUTHORITY_SERVER_URL.trim('/')}/$name"
return try {
Expand All @@ -118,6 +125,10 @@ object AuthorityFetcher {
}

private fun validateCache() {
if(!tryLockAuthoritiesFile()) {
return
}

val currentTime = System.currentTimeMillis()

if(!AUTHORITIES_FILE.exists()) {
Expand All @@ -132,16 +143,21 @@ object AuthorityFetcher {
logger.info("Authorities file has expired, clearing cache")
cache.clear()
}

AUTHORITIES_LOCK_FILE.unlock()
}

private fun saveAuthorityToFile(name: String, publicKey: String) {
if(!tryLockAuthoritiesFile()) {
return
}

try {
val sb = StringBuilder()

// Load existing authorities if the file exists
if (AUTHORITIES_FILE.exists()) {
val existingToml = AUTHORITIES_FILE.readText()

sb.append(existingToml)
}

Expand All @@ -151,12 +167,30 @@ object AuthorityFetcher {
sb.appendLine("timestamp = ${System.currentTimeMillis()}")

// Write the updated content to the file
AUTHORITIES_FILE.appendText(sb.toString())
SysUtil.saveFileStr(AUTHORITIES_FILE, sb.toString())
} catch (e: Exception) {
logger.error("Failed to save authority to file", e)
} finally {
AUTHORITIES_LOCK_FILE.unlock()
}
}

private fun tryLockAuthoritiesFile(): Boolean {
val time = System.currentTimeMillis()

logger.info("Trying to lock authorities file")

while(!AUTHORITIES_LOCK_FILE.tryLock(false) && System.currentTimeMillis() - time < AUTHORITIES_LOCK_FILE_TIMEOUT_MS) {
Thread.sleep(100)
}

if(!AUTHORITIES_LOCK_FILE.isLocked) {
logger.warn("Failed to lock authorities file")
}

return AUTHORITIES_LOCK_FILE.isLocked
}

fun parsePem(pem: String) =
pem.trim().lines().drop(1).dropLast(1).joinToString("")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
package io.github.deltacv.eocvsim.plugin.security.superaccess

import com.github.serivesmejia.eocvsim.util.JavaProcess
import com.github.serivesmejia.eocvsim.util.extension.hashString
import com.github.serivesmejia.eocvsim.util.loggerForThis
import org.java_websocket.WebSocket
import org.java_websocket.handshake.ClientHandshake
import org.java_websocket.server.WebSocketServer
import java.io.File
import java.lang.Exception
import java.net.InetSocketAddress
import java.util.Random
import java.util.concurrent.Executors
import java.util.concurrent.locks.Condition
import java.util.concurrent.locks.ReentrantLock
Expand All @@ -39,13 +41,35 @@ import kotlin.concurrent.withLock
typealias ResponseReceiver = (SuperAccessDaemon.SuperAccessResponse) -> Unit
typealias ResponseCondition = (SuperAccessDaemon.SuperAccessResponse) -> Boolean

class SuperAccessDaemonClient {
private data class AccessCache(
val head: String,
val file: String,
val hasAccess: Boolean,
val timestamp: Long,
val footer: String,
val count: Int,
val countIntegrity: String
) {

fun hash() = (head + file + hasAccess.toString() + timestamp.toString() + footer + count.toString() + countIntegrity).hashString

}

class SuperAccessDaemonClient(
val cacheTTLMillis: Long = 5000 // 5 seconds
) {

val logger by loggerForThis()

private val startLock = ReentrantLock()
val startCondition = startLock.newCondition()

private var cacheCount = Random().nextInt(Int.MAX_VALUE)
private var integrity = ""

private val cacheLock = Any()
private val accessCache = mutableMapOf<String, MutableList<AccessCache>>()

// create a new WebSocket server
private val server = WsServer(startLock, startCondition)

Expand Down Expand Up @@ -77,6 +101,35 @@ class SuperAccessDaemonClient {
}

fun checkAccess(file: File): Boolean {
synchronized(cacheLock) {
if (accessCache.containsKey(file.absolutePath)) {
val currentCaches = accessCache[file.absolutePath]!!
val currentCache = currentCaches.last()

if (System.currentTimeMillis() - currentCache.timestamp < cacheTTLMillis) {
val sortedCache = mutableListOf<AccessCache>()

for(caches in accessCache.values) {
sortedCache.addAll(caches)
}

sortedCache.sortBy { it.timestamp }

var expectedIntegrity = ""

for(cache in sortedCache) {
expectedIntegrity = (cache.hash() + expectedIntegrity).hashString
}

if (expectedIntegrity != integrity) {
throw SecurityException("Access cache has been tampered with")
}

return currentCache.hasAccess
}
}
}

val lock = ReentrantLock()
val condition = lock.newCondition()

Expand Down Expand Up @@ -105,13 +158,28 @@ class SuperAccessDaemonClient {
condition.await(3, java.util.concurrent.TimeUnit.SECONDS)
}

synchronized(cacheLock) {
val list = accessCache.getOrPut(file.absolutePath) { mutableListOf() }

val head = list.lastOrNull()?.hash() ?: ""

var countIntegrity = (cacheCount + (cacheCount - 1)).hashString

val newCache = AccessCache(head, file.absolutePath, hasAccess, System.currentTimeMillis(), integrity, cacheCount, countIntegrity).apply {
integrity = (hash() + integrity).hashString
cacheCount++
}

list.add(newCache)
}

return hasAccess
}

private class WsServer(
val startLock: ReentrantLock,
val startCondition: Condition,
) : WebSocketServer(InetSocketAddress(0)) {
) : WebSocketServer(InetSocketAddress("127.0.0.1", 0)) {
// create an executor with 1 thread
private val executor = Executors.newSingleThreadExecutor()

Expand Down
49 changes: 49 additions & 0 deletions EOCV-Sim/src/main/resources/.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
de las olas dulce, salina sea un amor,
colgadas las estrellas de tal perdición,
y la luz baila en sus ojos, que atraviesan,
por una noche triste, no será el dolor.

un beso de miel, por dos de caramelo,
suena cada toque que ellos no lamentan,
y el cielo cae en sus risas, que perdonan,
por una noche vieja, la que si fue ayer.

en la tumba del sol, seremos tan felices,
vuelan por las brisas de una nueva vida,
vuelan y aterrizan en otro frío octubre,
por una noche infinita, sea tan deprisa.

coronado el rey, en la luna y una tierra,
que ellos nunca dejarán de tal querer,
y el río deja de fluir, que no para de amar,
por una noche sola, sin luces de ciudad.

el no deja de quererlo, el no deja de amarlo,
un loco tan loco por unos ojos tan tristes,
un loco tan amado por su risa inconfundible,
por una noche de gracias, una nunca será.

sus brazos se rinden, la corriente los lleva,
sus dias e historias que no serán grises,
viento que habla, tiene mucho por decir,
por una noche en silencio, sola murmulla.

que se caiga el cielo, que brille en el limbo,
y amaría la manera como solías sostenerme,
de un toque lleno de amor, acaba en tristeza,
por una noche nuestra, bajo ninguna mirada.

tras un extraño silencio del sol ausente,
aquel que lamenta más que mil palabras,
¿y qué estaba pasando?, ¿ahora qué será?
por una noche sombría, en ella te veo bailar.

en tanto cariño por un solo dolor, de pronto,
una pizca de café que brilla en sus luces,
tanto que divagan sin saber sus nombres,
por una noche perdida, ¿en dónde estará?

se quiebra el infinito, parpadeo de instante,
bailando y brillando, sola en una ausencia,
sin sentir piedad, él se va sin mirar atrás,
y la noche es infinita, que no para de llorar.
Loading

0 comments on commit 15e7f07

Please sign in to comment.