Skip to content

Instantly share code, notes, and snippets.

@ccampores-n26
Last active December 28, 2024 15:54
Show Gist options
  • Save ccampores-n26/8e2edcb5d6e74d1cdb1d5c5f0f40423e to your computer and use it in GitHub Desktop.
Save ccampores-n26/8e2edcb5d6e74d1cdb1d5c5f0f40423e to your computer and use it in GitHub Desktop.
Demo FileHostingService
import java.time.Instant
data class File(
val filename: String,
val size: Int,
val createdAt: Long? = null,
val ttlSec: Long? = null
) {
fun isAlive(timestamp: Long): Boolean {
if (ttlSec == null || createdAt == null)
return true
val expiryDate = createdAt + (ttlSec * 1000)
return expiryDate > timestamp
}
}
class FileAlreadyExists(filename: String) : RuntimeException("File $filename already exists")
class FileNotFoundException(filename: String) : RuntimeException("File $filename doesn't exist")
class FileHostingService {
val files = mutableMapOf<String, File>()
val history = mutableListOf<Pair<Long, Map<String, File>>>()
fun upload(filename: String, size: Int) {
if (filename in files) {
throw FileAlreadyExists(filename)
}
files[filename] = File(filename, size)
backup()
}
fun uploadAt(filename: String, size: Int, timestamp: Long, ttlSec: Long? = null) {
if (filename in files) {
throw FileAlreadyExists(filename)
}
files[filename] = File(filename, size, createdAt = timestamp, ttlSec)
backup(timestamp)
}
fun get(name: String): Int? = files[name]?.size
fun getAt(name: String, timestamp: Long): Int? =
files[name]
?.takeIf { it.isAlive(timestamp) }
?.size
fun copy(source: String, dest: String) {
val oldFile = files[source] ?: throw FileNotFoundException(source)
files[dest] = oldFile
backup()
}
fun copyAt(source: String, dest: String, timestamp: Long) {
val oldFile = files[source]
?.takeIf { it.isAlive(timestamp) }
?: throw FileNotFoundException(source)
files[dest] = oldFile
backup(timestamp)
}
fun search(prefix: String): List<File> {
return files
.filter { it.key.startsWith(prefix) }
.map { it.value }
.sortedWith(
compareByDescending<File> { it.size }
.thenBy { it.filename }
)
.take(10)
}
fun searchAt(prefix: String, timestamp: Long): List<File> {
return files
.filter { it.key.startsWith(prefix) }
.map { it.value }
.filter { it.isAlive(timestamp) }
.sortedWith(
compareByDescending<File> { it.size }
.thenBy { it.filename }
)
.take(10)
}
fun rollback(timestamp: Long) {
val snapshot = history
.filter { it.first <= timestamp }
.maxByOrNull { it.first }
?.second ?: return
files.clear()
val modified = snapshot
.mapValues { (_, file) -> file.copy(createdAt = timestamp) }
files.putAll(modified)
}
private fun backup(timestamp: Long = Instant.now().toEpochMilli()) {
history.add(Pair(timestamp, files.toMap()))
}
}
fun main() {
val now = Instant.now()
val fh = FileHostingService()
for (i in 1..15) {
fh.uploadAt(
"f$i", 100,
now.minusSeconds(i.toLong()).toEpochMilli(),
5
)
}
// fh.searchAt("f", Instant.now().toEpochMilli())
// .forEach { println(it) }
val cutTime = now.plusSeconds(2)
fh.uploadAt("after", 100, cutTime.plusSeconds(2).toEpochMilli(), 3)
fh.files.forEach { println(it) }
println("------")
fh.history.forEach { println(it) }
println("------")
fh.rollback(cutTime.minusSeconds(6).toEpochMilli())
fh.files.forEach { println(it) }
val words = arrayOf("apple", "tisane")
words
.mapIndexed { index, w -> index to w }
.filter { (_, w) ->
w.startsWith("a") && w.endsWith("e")
}
.maxByOrNull { (index, _) -> index } ?: -1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment