Implemented seen command
This commit is contained in:
parent
d5000fa3c1
commit
3d49ebbd5f
11 changed files with 324 additions and 41 deletions
5
.idea/jarRepositories.xml
generated
5
.idea/jarRepositories.xml
generated
|
@ -16,6 +16,11 @@
|
||||||
<option name="name" value="MavenLocal" />
|
<option name="name" value="MavenLocal" />
|
||||||
<option name="url" value="file:$MAVEN_REPOSITORY$/" />
|
<option name="url" value="file:$MAVEN_REPOSITORY$/" />
|
||||||
</remote-repository>
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="MavenLocal" />
|
||||||
|
<option name="name" value="MavenLocal" />
|
||||||
|
<option name="url" value="file:$MAVEN_REPOSITORY$/" />
|
||||||
|
</remote-repository>
|
||||||
<remote-repository>
|
<remote-repository>
|
||||||
<option name="id" value="maven2" />
|
<option name="id" value="maven2" />
|
||||||
<option name="name" value="maven2" />
|
<option name="name" value="maven2" />
|
||||||
|
|
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
|
@ -1,5 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
|
<component name="FrameworkDetectionExcludesConfiguration">
|
||||||
|
<file type="web" url="file://$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="18" project-jdk-type="JavaSDK" />
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="18" project-jdk-type="JavaSDK" />
|
||||||
</project>
|
</project>
|
|
@ -52,11 +52,13 @@
|
||||||
<ID>NestedBlockDepth:LinksMgr.kt$LinksMgr$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID>
|
<ID>NestedBlockDepth:LinksMgr.kt$LinksMgr$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID>
|
||||||
<ID>NestedBlockDepth:Lookup.kt$Lookup$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID>
|
<ID>NestedBlockDepth:Lookup.kt$Lookup$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID>
|
||||||
<ID>NestedBlockDepth:Posting.kt$Posting$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID>
|
<ID>NestedBlockDepth:Posting.kt$Posting$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID>
|
||||||
|
<ID>NestedBlockDepth:Seen.kt$Seen$fun add(nick: String)</ID>
|
||||||
|
<ID>NestedBlockDepth:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID>
|
||||||
<ID>NestedBlockDepth:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID>
|
<ID>NestedBlockDepth:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID>
|
||||||
<ID>NestedBlockDepth:Tell.kt$Tell$fun send(event: GenericUserEvent)</ID>
|
<ID>NestedBlockDepth:Tell.kt$Tell$fun send(event: GenericUserEvent)</ID>
|
||||||
<ID>NestedBlockDepth:TellMessagesMgr.kt$TellMessagesMgr$@JvmStatic fun load(file: String): List<TellMessage></ID>
|
|
||||||
<ID>NestedBlockDepth:TellMessagesMgr.kt$TellMessagesMgr$@JvmStatic fun save(file: String, messages: List<TellMessage?>?)</ID>
|
|
||||||
<ID>NestedBlockDepth:TwitterOAuth.kt$TwitterOAuth$@JvmStatic @Throws(TwitterException::class, IOException::class) fun main(args: Array<String>)</ID>
|
<ID>NestedBlockDepth:TwitterOAuth.kt$TwitterOAuth$@JvmStatic @Throws(TwitterException::class, IOException::class) fun main(args: Array<String>)</ID>
|
||||||
|
<ID>NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun loadData(file: String, default: Any, logger: Logger, description: String): Any</ID>
|
||||||
|
<ID>NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun saveData(file: String, data: Any, logger: Logger, description: String)</ID>
|
||||||
<ID>NestedBlockDepth:Weather2.kt$Weather2$override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID>
|
<ID>NestedBlockDepth:Weather2.kt$Weather2$override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID>
|
||||||
<ID>NestedBlockDepth:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
<ID>NestedBlockDepth:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
||||||
<ID>ReturnCount:Addons.kt$Addons$fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean</ID>
|
<ID>ReturnCount:Addons.kt$Addons$fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean</ID>
|
||||||
|
|
|
@ -65,6 +65,7 @@ import net.thauvin.erik.mobibot.commands.links.LinksMgr
|
||||||
import net.thauvin.erik.mobibot.commands.links.Posting
|
import net.thauvin.erik.mobibot.commands.links.Posting
|
||||||
import net.thauvin.erik.mobibot.commands.links.Tags
|
import net.thauvin.erik.mobibot.commands.links.Tags
|
||||||
import net.thauvin.erik.mobibot.commands.links.View
|
import net.thauvin.erik.mobibot.commands.links.View
|
||||||
|
import net.thauvin.erik.mobibot.commands.seen.Seen
|
||||||
import net.thauvin.erik.mobibot.commands.tell.Tell
|
import net.thauvin.erik.mobibot.commands.tell.Tell
|
||||||
import net.thauvin.erik.mobibot.modules.Calc
|
import net.thauvin.erik.mobibot.modules.Calc
|
||||||
import net.thauvin.erik.mobibot.modules.CryptoPrices
|
import net.thauvin.erik.mobibot.modules.CryptoPrices
|
||||||
|
@ -113,7 +114,10 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
|
||||||
// Commands and Modules
|
// Commands and Modules
|
||||||
private val addons: Addons
|
private val addons: Addons
|
||||||
|
|
||||||
// Tell module
|
// Seen command
|
||||||
|
private val seen: Seen
|
||||||
|
|
||||||
|
// Tell command
|
||||||
private val tell: Tell
|
private val tell: Tell
|
||||||
|
|
||||||
/** Logger. */
|
/** Logger. */
|
||||||
|
@ -231,6 +235,8 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
|
||||||
with(event.getBot<PircBotX>()) {
|
with(event.getBot<PircBotX>()) {
|
||||||
if (user.nick == nick) {
|
if (user.nick == nick) {
|
||||||
LinksMgr.twitter.notification("$nick has left ${event.channel.name} on irc://$serverHostname")
|
LinksMgr.twitter.notification("$nick has left ${event.channel.name} on irc://$serverHostname")
|
||||||
|
} else {
|
||||||
|
seen.add(user.nick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,7 +259,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
|
||||||
Constants.PROPS_ARG,
|
Constants.PROPS_ARG,
|
||||||
Constants.PROPS_ARG.substring(0, 1),
|
Constants.PROPS_ARG.substring(0, 1),
|
||||||
"Use alternate properties file"
|
"Use alternate properties file"
|
||||||
).default("./mobibot.properties")
|
).default("./${ReleaseInfo.PROJECT}.properties")
|
||||||
val version by parser.option(
|
val version by parser.option(
|
||||||
ArgType.Boolean,
|
ArgType.Boolean,
|
||||||
Constants.VERSION_ARG,
|
Constants.VERSION_ARG,
|
||||||
|
@ -355,6 +361,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
|
||||||
nickservCustomMessage = identMsg
|
nickservCustomMessage = identMsg
|
||||||
}
|
}
|
||||||
isAutoReconnect = true
|
isAutoReconnect = true
|
||||||
|
|
||||||
//socketConnectTimeout = Constants.CONNECT_TIMEOUT
|
//socketConnectTimeout = Constants.CONNECT_TIMEOUT
|
||||||
//socketTimeout = Constants.CONNECT_TIMEOUT
|
//socketTimeout = Constants.CONNECT_TIMEOUT
|
||||||
//messageDelay = StaticDelay(500)
|
//messageDelay = StaticDelay(500)
|
||||||
|
@ -388,6 +395,11 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
|
||||||
addons.add(Posting())
|
addons.add(Posting())
|
||||||
addons.add(Recap())
|
addons.add(Recap())
|
||||||
addons.add(Say())
|
addons.add(Say())
|
||||||
|
|
||||||
|
// Seen command
|
||||||
|
seen = Seen("${logsDirPath}${nickname}-seen.ser")
|
||||||
|
addons.add(seen)
|
||||||
|
|
||||||
addons.add(Tags())
|
addons.add(Tags())
|
||||||
|
|
||||||
// Tell command
|
// Tell command
|
||||||
|
|
|
@ -38,18 +38,27 @@ import org.pircbotx.Colors
|
||||||
import org.pircbotx.PircBotX
|
import org.pircbotx.PircBotX
|
||||||
import org.pircbotx.hooks.events.PrivateMessageEvent
|
import org.pircbotx.hooks.events.PrivateMessageEvent
|
||||||
import org.pircbotx.hooks.types.GenericMessageEvent
|
import org.pircbotx.hooks.types.GenericMessageEvent
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import java.io.BufferedInputStream
|
||||||
|
import java.io.BufferedOutputStream
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
|
import java.io.ObjectInputStream
|
||||||
|
import java.io.ObjectOutputStream
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Paths
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
import java.util.stream.Collectors
|
import java.util.stream.Collectors
|
||||||
|
import kotlin.io.path.exists
|
||||||
|
import kotlin.io.path.fileSize
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Miscellaneous utilities.
|
* Miscellaneous utilities.
|
||||||
|
@ -188,6 +197,29 @@ object Utils {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load data.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun loadData(file: String, default: Any, logger: Logger, description: String): Any {
|
||||||
|
val serialFile = Paths.get(file)
|
||||||
|
if (serialFile.exists() && serialFile.fileSize() > 0) {
|
||||||
|
try {
|
||||||
|
ObjectInputStream(
|
||||||
|
BufferedInputStream(Files.newInputStream(serialFile))
|
||||||
|
).use { input ->
|
||||||
|
if (logger.isDebugEnabled) logger.debug("Loading the ${description}.")
|
||||||
|
return input.readObject()
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
logger.error("An IO error occurred loading the ${description}.", e)
|
||||||
|
} catch (e: ClassNotFoundException) {
|
||||||
|
logger.error("An error occurred loading the {$description}.", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return default
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@code true} if the list does not contain the given string.
|
* Returns {@code true} if the list does not contain the given string.
|
||||||
*/
|
*/
|
||||||
|
@ -238,6 +270,23 @@ object Utils {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun String?.reverseColor(): String = colorize(Colors.REVERSE)
|
fun String?.reverseColor(): String = colorize(Colors.REVERSE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save data
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun saveData(file: String, data: Any, logger: Logger, description: String) {
|
||||||
|
try {
|
||||||
|
BufferedOutputStream(Files.newOutputStream(Paths.get(file))).use { bos ->
|
||||||
|
ObjectOutputStream(bos).use { output ->
|
||||||
|
if (logger.isDebugEnabled) logger.debug("Saving the ${description}.")
|
||||||
|
output.writeObject(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
logger.error("Unable to save the ${description}.", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a formatted commands/modules, etc. list.
|
* Send a formatted commands/modules, etc. list.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -63,7 +63,7 @@ class Info(private val tell: Tell) : AbstractCommand() {
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun Long.toUptime(): String {
|
fun Long.toUptime(): String {
|
||||||
this.toDuration(DurationUnit.MILLISECONDS).toComponents { wholeDays, hours, minutes, _, _ ->
|
this.toDuration(DurationUnit.MILLISECONDS).toComponents { wholeDays, hours, minutes, seconds, _ ->
|
||||||
val years = wholeDays / 365
|
val years = wholeDays / 365
|
||||||
var days = wholeDays % 365
|
var days = wholeDays % 365
|
||||||
val months = days / 30
|
val months = days / 30
|
||||||
|
@ -88,7 +88,11 @@ class Info(private val tell: Tell) : AbstractCommand() {
|
||||||
append(hours).append(" hour".plural(hours.toLong())).append(' ')
|
append(hours).append(" hour".plural(hours.toLong())).append(' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (minutes > 0) {
|
||||||
append(minutes).append(" minute".plural(minutes.toLong()))
|
append(minutes).append(" minute".plural(minutes.toLong()))
|
||||||
|
} else {
|
||||||
|
append(seconds).append(" second".plural(seconds.toLong()))
|
||||||
|
}
|
||||||
|
|
||||||
return toString()
|
return toString()
|
||||||
}
|
}
|
||||||
|
|
118
src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt
Normal file
118
src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Seen.kt
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net)
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of this project nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.thauvin.erik.mobibot.commands.seen
|
||||||
|
|
||||||
|
import net.thauvin.erik.mobibot.Utils.bot
|
||||||
|
import net.thauvin.erik.mobibot.Utils.helpFormat
|
||||||
|
import net.thauvin.erik.mobibot.Utils.loadData
|
||||||
|
import net.thauvin.erik.mobibot.Utils.saveData
|
||||||
|
import net.thauvin.erik.mobibot.Utils.sendMessage
|
||||||
|
import net.thauvin.erik.mobibot.commands.AbstractCommand
|
||||||
|
import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime
|
||||||
|
import org.pircbotx.hooks.types.GenericMessageEvent
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
|
class Seen(private val serialObject: String) : AbstractCommand() {
|
||||||
|
private val logger: Logger = LoggerFactory.getLogger(Seen::class.java)
|
||||||
|
val seenNicks: MutableList<SeenNick> = mutableListOf()
|
||||||
|
|
||||||
|
override val name = "seen"
|
||||||
|
override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name <nick>"))
|
||||||
|
override val isOpOnly = false
|
||||||
|
override val isPublic = true
|
||||||
|
override val isVisible = true
|
||||||
|
|
||||||
|
override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
|
||||||
|
if (isEnabled()) {
|
||||||
|
if (args.isNotBlank() && !args.contains(' ')) {
|
||||||
|
val ch = event.bot().userChannelDao.getChannel(channel)
|
||||||
|
ch.users.forEach {
|
||||||
|
if (args.equals(it.nick, true)) {
|
||||||
|
event.sendMessage("${it.nick} is on ${channel}.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seenNicks.forEach {
|
||||||
|
if (it.nick.equals(args, true)) {
|
||||||
|
val lastSeen = System.currentTimeMillis() - it.last
|
||||||
|
event.sendMessage("${it.nick} was last seen on $channel ${lastSeen.toUptime()} ago.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.sendMessage("I haven't seen $args on $channel lately.")
|
||||||
|
} else {
|
||||||
|
helpResponse(channel, args, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(nick: String) {
|
||||||
|
if (isEnabled()) {
|
||||||
|
seenNicks.forEach {
|
||||||
|
if (it.nick.equals(nick, true)) {
|
||||||
|
if (it.nick != nick) it.nick = nick
|
||||||
|
it.last = System.currentTimeMillis()
|
||||||
|
save()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seenNicks.add(SeenNick(nick))
|
||||||
|
save()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
seenNicks.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun load() {
|
||||||
|
if (isEnabled()) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
seenNicks += loadData(
|
||||||
|
serialObject,
|
||||||
|
mutableListOf<SeenNick>(),
|
||||||
|
logger,
|
||||||
|
"seen nicknames"
|
||||||
|
) as MutableList<SeenNick>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun save() {
|
||||||
|
saveData(serialObject, seenNicks, logger, "seen nicknames")
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* SeenNick.kt
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net)
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of this project nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.thauvin.erik.mobibot.commands.seen
|
||||||
|
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
data class SeenNick(var nick: String, var last: Long = System.currentTimeMillis()) : Serializable {
|
||||||
|
companion object {
|
||||||
|
private const val serialVersionUID = 1L
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,18 +31,12 @@
|
||||||
*/
|
*/
|
||||||
package net.thauvin.erik.mobibot.commands.tell
|
package net.thauvin.erik.mobibot.commands.tell
|
||||||
|
|
||||||
|
import net.thauvin.erik.mobibot.Utils.loadData
|
||||||
|
import net.thauvin.erik.mobibot.Utils.saveData
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.BufferedInputStream
|
|
||||||
import java.io.BufferedOutputStream
|
|
||||||
import java.io.IOException
|
|
||||||
import java.io.ObjectInputStream
|
|
||||||
import java.io.ObjectOutputStream
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.Paths
|
|
||||||
import java.time.Clock
|
import java.time.Clock
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import kotlin.io.path.exists
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Tell Messages Manager.
|
* The Tell Messages Manager.
|
||||||
|
@ -65,23 +59,8 @@ object TellMessagesMgr {
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun load(file: String): List<TellMessage> {
|
fun load(file: String): List<TellMessage> {
|
||||||
val serialFile = Paths.get(file)
|
|
||||||
if (serialFile.exists()) {
|
|
||||||
try {
|
|
||||||
ObjectInputStream(
|
|
||||||
BufferedInputStream(Files.newInputStream(serialFile))
|
|
||||||
).use { input ->
|
|
||||||
if (logger.isDebugEnabled) logger.debug("Loading the messages.")
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return input.readObject() as List<TellMessage>
|
return loadData(file, emptyList<TellMessage>(), logger, "message queue") as List<TellMessage>
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
logger.error("An IO error occurred loading the messages queue.", e)
|
|
||||||
} catch (e: ClassNotFoundException) {
|
|
||||||
logger.error("An error occurred loading the messages queue.", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listOf()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,15 +68,8 @@ object TellMessagesMgr {
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun save(file: String, messages: List<TellMessage?>?) {
|
fun save(file: String, messages: List<TellMessage?>?) {
|
||||||
try {
|
if (messages != null) {
|
||||||
BufferedOutputStream(Files.newOutputStream(Paths.get(file))).use { bos ->
|
saveData(file, messages, logger, "messages")
|
||||||
ObjectOutputStream(bos).use { output ->
|
|
||||||
if (logger.isDebugEnabled) logger.debug("Saving the messages.")
|
|
||||||
output.writeObject(messages)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
logger.error("Unable to save messages queue.", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,8 @@ class InfoTest {
|
||||||
assertThat(1320300000L.toUptime(), "weeks days hours minutes").isEqualTo("2 weeks 1 day 6 hours 45 minutes")
|
assertThat(1320300000L.toUptime(), "weeks days hours minutes").isEqualTo("2 weeks 1 day 6 hours 45 minutes")
|
||||||
assertThat(2700000L.toUptime(), "45 minutes").isEqualTo("45 minutes")
|
assertThat(2700000L.toUptime(), "45 minutes").isEqualTo("45 minutes")
|
||||||
assertThat(60000L.toUptime(), "1 minute").isEqualTo("1 minute")
|
assertThat(60000L.toUptime(), "1 minute").isEqualTo("1 minute")
|
||||||
assertThat(0L.toUptime(), "0 minute").isEqualTo("0 minute")
|
assertThat(59000L.toUptime(), "59 seconds").isEqualTo("59 seconds")
|
||||||
|
assertThat(0L.toUptime(), "0 second").isEqualTo("0 second")
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* SeenTest.kt
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2022, Erik C. Thauvin (erik@thauvin.net)
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of this project nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.thauvin.erik.mobibot.commands.seen
|
||||||
|
|
||||||
|
import assertk.assertThat
|
||||||
|
import assertk.assertions.isEqualTo
|
||||||
|
import assertk.assertions.isGreaterThan
|
||||||
|
import assertk.assertions.isTrue
|
||||||
|
import org.testng.annotations.AfterClass
|
||||||
|
import org.testng.annotations.BeforeClass
|
||||||
|
import org.testng.annotations.Test
|
||||||
|
import kotlin.io.path.deleteIfExists
|
||||||
|
import kotlin.io.path.fileSize
|
||||||
|
|
||||||
|
class SeenTest {
|
||||||
|
private val tmpFile = kotlin.io.path.createTempFile(suffix = ".ser")
|
||||||
|
private val seen = Seen(tmpFile.toAbsolutePath().toString())
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
fun saveTest() {
|
||||||
|
seen.add("ErikT")
|
||||||
|
assertThat(tmpFile.fileSize(), "temporary file is empty").isGreaterThan(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass(alwaysRun = true)
|
||||||
|
fun afterClass() {
|
||||||
|
tmpFile.deleteIfExists()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun loadTest() {
|
||||||
|
val nick = seen.seenNicks[0]
|
||||||
|
seen.clear()
|
||||||
|
seen.load()
|
||||||
|
assertThat(seen.seenNicks[0] == nick, "nick is different").isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(priority = 10)
|
||||||
|
fun clearTest() {
|
||||||
|
seen.clear()
|
||||||
|
seen.save()
|
||||||
|
seen.load()
|
||||||
|
assertThat(seen.seenNicks.size, "nicknames are not empty.").isEqualTo(0)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue