mirror of
https://github.com/tursom/TursomServer.git
synced 2025-01-17 07:40:37 +08:00
添加mail read库;为Parser添加对Set的支持;完善Yaml.toYaml方法
This commit is contained in:
parent
a19d4f12d2
commit
654d721428
@ -10,75 +10,106 @@ object Parser {
|
||||
|
||||
fun <T> parse(yaml: Any, clazz: Class<T>): T? {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return if (yaml is List<*> && clazz.isArray) {
|
||||
parseArray(yaml, clazz) as T
|
||||
} else when (clazz) {
|
||||
Any::class.java -> yaml
|
||||
Int::class.java -> yaml.toInt()
|
||||
Long::class.java -> yaml.toLong()
|
||||
Float::class.java -> yaml.toFloat()
|
||||
Double::class.java -> yaml.toDouble()
|
||||
Boolean::class.java -> yaml.toBoolean()
|
||||
|
||||
getClazz<Int>() -> yaml.toInt()
|
||||
getClazz<Long>() -> yaml.toLong()
|
||||
getClazz<Float>() -> yaml.toFloat()
|
||||
getClazz<Double>() -> yaml.toDouble()
|
||||
getClazz<Boolean>() -> yaml.toBoolean()
|
||||
String::class.java -> yaml.toString()
|
||||
|
||||
else -> {
|
||||
if (yaml !is Map<*, *>) return null
|
||||
val instance = try {
|
||||
clazz.newInstance()
|
||||
} catch (e: Exception) {
|
||||
unsafe.allocateInstance(clazz)
|
||||
}
|
||||
val fields = clazz.declaredFields
|
||||
fields.forEach {
|
||||
if ((it.modifiers and (Modifier.STATIC or Modifier.TRANSIENT)) != 0) return@forEach
|
||||
try {
|
||||
val parse = parseField(yaml[it.name] ?: return@forEach, it) ?: return@forEach
|
||||
it.isAccessible = true
|
||||
it.set(instance, parse)
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
instance
|
||||
return when {
|
||||
clazz.isInstance(yaml) -> yaml.cast()
|
||||
clazz.isInheritanceFrom(Enum::class.java) -> try {
|
||||
val valueOf = clazz.getDeclaredMethod("valueOf", String::class.java)
|
||||
valueOf.invoke(null, yaml.toString().toUpperCase()) as T
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
} as T
|
||||
yaml is List<*> && clazz.isArray -> parseArray(yaml, clazz) as T
|
||||
else -> when (clazz) {
|
||||
Any::class.java -> yaml
|
||||
Int::class.java -> yaml.toInt()
|
||||
Long::class.java -> yaml.toLong()
|
||||
Float::class.java -> yaml.toFloat()
|
||||
Double::class.java -> yaml.toDouble()
|
||||
Boolean::class.java -> yaml.toBoolean()
|
||||
|
||||
getClazz<Int>() -> yaml.toInt()
|
||||
getClazz<Long>() -> yaml.toLong()
|
||||
getClazz<Float>() -> yaml.toFloat()
|
||||
getClazz<Double>() -> yaml.toDouble()
|
||||
getClazz<Boolean>() -> yaml.toBoolean()
|
||||
String::class.java -> yaml.toString()
|
||||
|
||||
else -> {
|
||||
if (yaml !is Map<*, *>) return null
|
||||
val instance = try {
|
||||
clazz.newInstance()
|
||||
} catch (e: Exception) {
|
||||
unsafe.allocateInstance(clazz)
|
||||
}
|
||||
val fields = clazz.declaredFields
|
||||
fields.forEach {
|
||||
if ((it.modifiers and (Modifier.STATIC or Modifier.TRANSIENT)) != 0) return@forEach
|
||||
try {
|
||||
val parse = parseField(yaml[it.name] ?: return@forEach, it) ?: return@forEach
|
||||
it.isAccessible = true
|
||||
it.set(instance, parse)
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
instance
|
||||
}
|
||||
} as T
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseField(yaml: Any, field: Field): Any? {
|
||||
val clazz = field.type
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return if (yaml is List<*>) {
|
||||
when {
|
||||
clazz.isAssignableFrom(List::class.java) -> {
|
||||
val type = field.actualTypeArguments
|
||||
if (type == Any::class.java) {
|
||||
yaml
|
||||
} else {
|
||||
val list = try {
|
||||
clazz.newInstance() as MutableList<Any>
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
unsafe.allocateInstance(clazz) as MutableList<Any>
|
||||
return when (yaml) {
|
||||
is List<*> -> {
|
||||
when {
|
||||
clazz.isAssignableFrom(List::class.java) -> {
|
||||
val type = field.actualTypeArguments
|
||||
if (type == Any::class.java) {
|
||||
yaml
|
||||
} else {
|
||||
val list = try {
|
||||
clazz.newInstance() as MutableList<Any>
|
||||
} catch (e: Exception) {
|
||||
ArrayList<Any>()
|
||||
try {
|
||||
unsafe.allocateInstance(clazz) as MutableList<Any>
|
||||
} catch (e: Exception) {
|
||||
ArrayList<Any>()
|
||||
}
|
||||
}
|
||||
yaml.forEach {
|
||||
list.add(parse(it ?: return@forEach, type) ?: return@forEach)
|
||||
}
|
||||
list
|
||||
}
|
||||
yaml.forEach {
|
||||
list.add(parse(it ?: return@forEach, type) ?: return@forEach)
|
||||
}
|
||||
list
|
||||
}
|
||||
clazz.isAssignableFrom(Set::class.java) -> {
|
||||
val type = field.actualTypeArguments
|
||||
if (type == Any::class.java) {
|
||||
yaml
|
||||
} else {
|
||||
val set: MutableSet<Any> = try {
|
||||
clazz.newInstance() as MutableSet<Any>
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
unsafe.allocateInstance(clazz) as MutableSet<Any>
|
||||
} catch (e: Exception) {
|
||||
HashSet()
|
||||
}
|
||||
}
|
||||
yaml.forEach {
|
||||
set.add(parse(it ?: return@forEach, type) ?: return@forEach)
|
||||
}
|
||||
set
|
||||
}
|
||||
}
|
||||
clazz.isArray -> parseArray(yaml, clazz)
|
||||
else -> null
|
||||
}
|
||||
clazz.isArray -> parseArray(yaml, clazz)
|
||||
else -> null
|
||||
}
|
||||
} else {
|
||||
parse(yaml, clazz)
|
||||
else -> {
|
||||
parse(yaml, clazz)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ import javax.activation.DataHandler
|
||||
import javax.activation.FileDataSource
|
||||
import javax.mail.Address
|
||||
import javax.mail.Session
|
||||
import javax.mail.event.TransportEvent
|
||||
import javax.mail.event.TransportListener
|
||||
import javax.mail.internet.InternetAddress
|
||||
import javax.mail.internet.MimeBodyPart
|
||||
|
120
utils/mail/src/main/kotlin/cn/tursom/mail/read.kt
Normal file
120
utils/mail/src/main/kotlin/cn/tursom/mail/read.kt
Normal file
@ -0,0 +1,120 @@
|
||||
package cn.tursom.mail
|
||||
|
||||
import java.nio.charset.Charset
|
||||
import java.util.concurrent.ScheduledFuture
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor
|
||||
import java.util.concurrent.ThreadFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.mail.*
|
||||
import javax.mail.event.MessageCountListener
|
||||
import javax.mail.internet.InternetAddress
|
||||
|
||||
private val threadPool by lazy {
|
||||
ScheduledThreadPoolExecutor(
|
||||
1,
|
||||
ThreadFactory { Thread(it, "MailLoop") })
|
||||
}
|
||||
|
||||
fun addMailListener(
|
||||
folder: Folder,
|
||||
freq: Long, timeUnit: TimeUnit,
|
||||
listener: MessageCountListener,
|
||||
newFolder: () -> Folder? = { null }
|
||||
): ScheduledFuture<*> {
|
||||
folder.addMessageCountListener(listener)
|
||||
var mailFOlder = folder
|
||||
return threadPool.scheduleAtFixedRate({
|
||||
try {
|
||||
mailFOlder.messageCount
|
||||
} catch (e: FolderClosedException) {
|
||||
mailFOlder = newFolder() ?: throw e
|
||||
mailFOlder.addMessageCountListener(listener)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
throw e
|
||||
}
|
||||
}, 0, freq, timeUnit)
|
||||
}
|
||||
|
||||
fun addMailListener(
|
||||
newFolder: () -> Folder,
|
||||
freq: Long, timeUnit: TimeUnit,
|
||||
listener: MessageCountListener
|
||||
): ScheduledFuture<*> = addMailListener(newFolder(), freq, timeUnit, listener, newFolder)
|
||||
|
||||
fun getStore(host: String, port: Int, account: String, password: String): Store {
|
||||
val props = System.getProperties()
|
||||
props["mail.imap.host"] = host
|
||||
props["mail.imap.port"] = port
|
||||
props["mail.imap.auth"] = "true"
|
||||
props["mail.imap.ssl.enable"] = "true"
|
||||
props["mail.imap.socketFactory.port"] = port
|
||||
props["mail.imap.socketFactory.fallback"] = "false"
|
||||
props["mail.imap.socketFactory.class"] = "javax.net.ssl.SSLSocketFactory"
|
||||
val session = Session.getDefaultInstance(props)
|
||||
val store = session.getStore("imap")
|
||||
store.connect(account, password)
|
||||
return store
|
||||
}
|
||||
|
||||
fun getFolder(host: String, port: Int, account: String, password: String): Pair<Store, Folder> {
|
||||
val store: Store = getStore(host, port, account, password)
|
||||
val folder: Folder = store.getFolder("INBOX")
|
||||
folder.open(Folder.READ_ONLY)
|
||||
return store to folder
|
||||
}
|
||||
|
||||
fun forEachMail(host: String, port: Int, account: String, password: String, onMsg: (msg: Message) -> Unit) {
|
||||
val (store, folder) = getFolder(host, port, account, password)
|
||||
// 全部邮件数
|
||||
val messages: Array<Message> = folder.messages
|
||||
messages.forEach(onMsg)
|
||||
folder.close(true)
|
||||
store.close()
|
||||
}
|
||||
|
||||
fun getText(message: Message): String? = when (val content: Any = message.content) {
|
||||
is String -> content
|
||||
is Multipart -> {
|
||||
val sb = StringBuilder()
|
||||
repeat(content.count) {
|
||||
val part: Part = content.getBodyPart(it)
|
||||
if (part.contentType.contains("text/plain")) {
|
||||
var charsetStart = part.contentType.indexOf("charset=", 0, true)
|
||||
if (charsetStart != -1) charsetStart += "charset=".length
|
||||
var charsetEnd = part.contentType.indexOf(';', charsetStart)
|
||||
if (charsetEnd == -1) {
|
||||
charsetEnd = part.contentType.length
|
||||
}
|
||||
val msg = part.inputStream.bufferedReader(
|
||||
if (charsetStart == -1) {
|
||||
Charsets.UTF_8
|
||||
} else {
|
||||
Charset.forName(part.contentType.substring(charsetStart, charsetEnd))
|
||||
}
|
||||
).readText()
|
||||
sb.append(msg)
|
||||
}
|
||||
}
|
||||
if (sb.isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
sb.toString()
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun forEachUnreadMail(host: String, port: Int, account: String, password: String, onMsg: (from: InternetAddress, msg: String) -> Boolean) {
|
||||
forEachMail(host, port, account, password) { message ->
|
||||
// 跳过已读邮件
|
||||
if (message.flags.contains(Flags.Flag.SEEN)) return@forEachMail
|
||||
val msg = getText(message)
|
||||
val read = when (val text = getText(message)) {
|
||||
null -> false
|
||||
else -> onMsg(message.from[0] as InternetAddress, text)
|
||||
}
|
||||
//未读邮件标记为已读
|
||||
message.setFlag(Flags.Flag.SEEN, read)
|
||||
}
|
||||
}
|
@ -16,57 +16,78 @@ object Yaml {
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
|
||||
private fun toYaml(obj: Any, stringBuilder: StringBuilder, indentation: String) {
|
||||
private fun toYaml(obj: Any, stringBuilder: StringBuilder, indentation: String, inCollection: Boolean = false) {
|
||||
when (obj) {
|
||||
is Byte -> stringBuilder.append("$obj")
|
||||
is Char -> stringBuilder.append("$obj")
|
||||
is Short -> stringBuilder.append("$obj")
|
||||
is Int -> stringBuilder.append("$obj")
|
||||
is Long -> stringBuilder.append("$obj")
|
||||
is Float -> stringBuilder.append("$obj")
|
||||
is Double -> stringBuilder.append("$obj")
|
||||
is String -> stringBuilder.append("$obj")
|
||||
is Collection<*> -> obj.forEach {
|
||||
it ?: return@forEach
|
||||
stringBuilder.append("$indentation- ")
|
||||
toYaml(it, stringBuilder, "$indentation ")
|
||||
if (!stringBuilder.endsWith('\n')) {
|
||||
stringBuilder.append("\n")
|
||||
is Byte -> stringBuilder.append(obj)
|
||||
is Char -> stringBuilder.append(obj)
|
||||
is Short -> stringBuilder.append(obj)
|
||||
is Int -> stringBuilder.append(obj)
|
||||
is Long -> stringBuilder.append(obj)
|
||||
is Float -> stringBuilder.append(obj)
|
||||
is Double -> stringBuilder.append(obj)
|
||||
is String -> stringBuilder.append(obj)
|
||||
is Map<*, *> -> {
|
||||
var first = true
|
||||
obj.forEach { (any, u) ->
|
||||
if (inCollection && first) {
|
||||
stringBuilder.append("${any ?: return@forEach}: ")
|
||||
first = false
|
||||
} else {
|
||||
stringBuilder.append("$indentation${any ?: return@forEach}: ")
|
||||
}
|
||||
toYaml(u ?: return@forEach, stringBuilder, "$indentation ")
|
||||
if (!stringBuilder.endsWith('\n')) {
|
||||
stringBuilder.append("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
is Map<*, *> -> obj.forEach { (any, u) ->
|
||||
stringBuilder.append("$indentation${any ?: return@forEach}: ")
|
||||
toYaml(u ?: return@forEach, stringBuilder, "$indentation ")
|
||||
if (!stringBuilder.endsWith('\n')) {
|
||||
stringBuilder.append("\n")
|
||||
is Collection<*> -> if (obj.isEmpty()) {
|
||||
stringBuilder.append("[]")
|
||||
} else {
|
||||
var appended = 0
|
||||
obj.forEach {
|
||||
it ?: return@forEach
|
||||
stringBuilder.append("${if (appended == 0) '\n' else ""}$indentation- ")
|
||||
appended++
|
||||
toYaml(it, stringBuilder, "$indentation ", true)
|
||||
if (!stringBuilder.endsWith('\n')) {
|
||||
stringBuilder.append("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
var first = true
|
||||
fun getIndentation() = if (inCollection && first) {
|
||||
first = false
|
||||
""
|
||||
} else {
|
||||
indentation
|
||||
}
|
||||
obj.javaClass.declaredFields.forEach {
|
||||
if ((it.modifiers and (Modifier.STATIC or Modifier.TRANSIENT)) != 0) return@forEach
|
||||
it.isAccessible = true
|
||||
val value = it.get(obj)
|
||||
when (it.type) {
|
||||
Byte::class.java -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
Char::class.java -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
Short::class.java -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
Int::class.java -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
Long::class.java -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
Float::class.java -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
Double::class.java -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
Byte::class.java -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
Char::class.java -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
Short::class.java -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
Int::class.java -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
Long::class.java -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
Float::class.java -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
Double::class.java -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
|
||||
getClazz<Byte>() -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
getClazz<Char>() -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
getClazz<Short>() -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
getClazz<Int>() -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
getClazz<Long>() -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
getClazz<Float>() -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
getClazz<Double>() -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
String::class.java -> stringBuilder.append("$indentation${it.name}: $value\n")
|
||||
getClazz<Byte>() -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
getClazz<Char>() -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
getClazz<Short>() -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
getClazz<Int>() -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
getClazz<Long>() -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
getClazz<Float>() -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
getClazz<Double>() -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
String::class.java -> stringBuilder.append("${getIndentation()}${it.name}: $value\n")
|
||||
|
||||
else -> {
|
||||
stringBuilder.append("$indentation${it.name}:\n")
|
||||
toYaml(value, stringBuilder, "$indentation ")
|
||||
stringBuilder.append("${getIndentation()}${it.name}: ")
|
||||
toYaml(value, stringBuilder, "${getIndentation()} ")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -81,7 +102,6 @@ object Yaml {
|
||||
inline fun <reified T> parseResource(classLoader: ClassLoader, path: String) = parseResource(classLoader, path, T::class.java)
|
||||
|
||||
fun <T> parseResource(path: String, clazz: Class<T>) = parseResource(this.javaClass.classLoader, path, clazz)
|
||||
fun <T> parseResource(classLoader: ClassLoader, path: String, clazz: Class<T>) = Parser.parse(yaml.load<Any>(classLoader.getResourceAsStream(path)), clazz)
|
||||
fun <T> parse(yaml: String, clazz: Class<T>) = Parser.parse(this.yaml.load<Any>(yaml), clazz)
|
||||
|
||||
fun <T> parseResource(classLoader: ClassLoader, path: String, clazz: Class<T>) = Parser.parse(yaml.load(classLoader.getResourceAsStream(path)), clazz)
|
||||
fun <T> parse(yaml: String, clazz: Class<T>) = Parser.parse(this.yaml.load(yaml), clazz)
|
||||
}
|
Loading…
Reference in New Issue
Block a user