-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathStorage.kt
More file actions
163 lines (139 loc) · 5.77 KB
/
Copy pathStorage.kt
File metadata and controls
163 lines (139 loc) · 5.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package org.openredstone.chattore
import kotlinx.serialization.json.Json
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.transactions.transaction
import org.openredstone.chattore.feature.MailboxItem
import org.openredstone.chattore.feature.NickPreset
import org.openredstone.chattore.feature.ShowGlobalChatInBubble
import java.nio.file.Path
import java.util.*
import java.util.concurrent.ConcurrentHashMap
object About : Table("about") {
val uuid = varchar("about_uuid", 36).uniqueIndex()
val about = varchar("about_about", 512)
override val primaryKey = PrimaryKey(uuid)
}
object Mail : Table("mail") {
val id = integer("mail_id").autoIncrement()
val timestamp = integer("mail_timestamp")
val sender = varchar("mail_sender", 36).index()
val recipient = varchar("mail_recipient", 36).index()
val read = bool("mail_read").default(false)
val message = varchar("mail_message", 512)
override val primaryKey = PrimaryKey(id)
}
object Nick : Table("nick") {
val uuid = varchar("nick_uuid", 36).uniqueIndex()
val nick = varchar("nick_nick", 2048)
override val primaryKey = PrimaryKey(uuid)
}
object UsernameCache : Table("username_cache") {
val uuid = varchar("cache_user", 36).uniqueIndex()
val username = varchar("cache_username", 16).index()
override val primaryKey = PrimaryKey(uuid)
}
object JsonSetting : Table("setting") {
val uuid = varchar("setting_uuid", 36).index()
val key = varchar("setting_key", 32).index()
val value = text("setting_value")
val uuidKeyIndex = index("setting_uuid_key_index", true, uuid, key)
}
class Setting<T>(val key: String)
class Storage(
dbFile: Path,
) {
private val cacheLength = 86400 // One day
private val nicknameCache = ConcurrentHashMap<UUID, Pair<NickPreset, Long>>()
val database = Database.connect("jdbc:sqlite:${dbFile.toAbsolutePath()}", "org.sqlite.JDBC")
init {
initTables()
}
private fun initTables() = transaction(database) {
SchemaUtils.create(
About, Mail, Nick, UsernameCache, JsonSetting
)
}
fun setAbout(uuid: UUID, about: String) = transaction(database) {
About.upsert {
it[this.uuid] = uuid.toString()
it[this.about] = about
}
}
fun getAbout(uuid: UUID): String? = transaction(database) {
About.selectAll().where { About.uuid eq uuid.toString() }.firstOrNull()?.let { it[About.about] }
}
fun removeNickname(target: UUID) = transaction(database) {
Nick.deleteWhere { Nick.uuid eq target.toString() }
nicknameCache.remove(target)
}
fun getNickname(target: UUID): NickPreset? = transaction(database) {
val nickname = nicknameCache[target]?.first ?: run {
Nick.selectAll().where { Nick.uuid eq target.toString() }.firstOrNull()?.let { NickPreset(it[Nick.nick]) }
}
if (nickname != null) cacheNickname(target, nickname)
nickname
}
fun setNickname(target: UUID, nickname: NickPreset) = transaction(database) {
Nick.upsert {
it[this.uuid] = target.toString()
it[this.nick] = nickname.miniMessageFormat
}
cacheNickname(target, nickname)
}
private fun cacheNickname(target: UUID, nickname: NickPreset) {
val now = System.currentTimeMillis() / 1000
nicknameCache.entries.removeIf { it.value.second + cacheLength < now }
nicknameCache[target] = Pair(nickname, now)
}
fun insertMessage(sender: UUID, recipient: UUID, message: String) = transaction(database) {
Mail.insert {
it[this.timestamp] = System.currentTimeMillis().floorDiv(1000).toInt()
it[this.sender] = sender.toString()
it[this.recipient] = recipient.toString()
it[this.message] = message
}
}
fun readMessage(recipient: UUID, id: Int): Pair<UUID, String>? = transaction(database) {
Mail.selectAll().where { (Mail.id eq id) and (Mail.recipient eq recipient.toString()) }
.firstOrNull()?.let { toReturn ->
markRead(id, true)
UUID.fromString(toReturn[Mail.sender]) to toReturn[Mail.message]
}
}
fun getMessages(recipient: UUID): List<MailboxItem> = transaction(database) {
Mail.selectAll().where { Mail.recipient eq recipient.toString() }
.orderBy(Mail.timestamp to SortOrder.DESC).map {
MailboxItem(
it[Mail.id],
it[Mail.timestamp],
UUID.fromString(it[Mail.sender]),
it[Mail.read]
)
}
}
private fun markRead(id: Int, read: Boolean) = transaction(database) {
Mail.update({ Mail.id eq id }) {
it[this.read] = read
}
}
inline fun <reified T> setSetting(setting: Setting<T>, uuid: UUID, value: T) = transaction(database) {
JsonSetting.upsert {
it[JsonSetting.uuid] = uuid.toString()
it[key] = setting.key
it[JsonSetting.value] = Json.encodeToString(value)
}
}
inline fun <reified T> getSetting(setting: Setting<T>, uuid: UUID): T? = transaction {
val result = JsonSetting.selectAll().where {
(JsonSetting.uuid eq uuid.toString()) and (JsonSetting.key eq setting.key)
}.singleOrNull() ?: return@transaction null
val jsonString = result[JsonSetting.value]
Json.decodeFromString<T>(jsonString)
}
fun getAllGlobalChatEnabled(): Set<UUID> = transaction(database) {
JsonSetting.selectAll().where {
(JsonSetting.key eq ShowGlobalChatInBubble.key) and (JsonSetting.value eq Json.encodeToString(true))
}.map { UUID.fromString(it[JsonSetting.uuid]) }.toSet()
}
}