Seen is now keeping track of nicks using a TreeMap on various events (nick change, join, etc.)
This commit is contained in:
parent
145749408b
commit
f35313bf62
8 changed files with 108 additions and 33 deletions
|
@ -173,6 +173,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
|
||||||
event?.let {
|
event?.let {
|
||||||
with(event.getBot<PircBotX>()) {
|
with(event.getBot<PircBotX>()) {
|
||||||
LinksMgr.twitter.notification("$nick disconnected from irc://$serverHostname")
|
LinksMgr.twitter.notification("$nick disconnected from irc://$serverHostname")
|
||||||
|
seen.add(userChannelDao.getChannel(channel).users)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LinksMgr.twitter.shutdown()
|
LinksMgr.twitter.shutdown()
|
||||||
|
@ -197,8 +198,10 @@ 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 joined ${event.channel.name} on irc://$serverHostname")
|
LinksMgr.twitter.notification("$nick has joined ${event.channel.name} on irc://$serverHostname")
|
||||||
|
seen.add(userChannelDao.getChannel(channel).users)
|
||||||
} else {
|
} else {
|
||||||
tell.send(event)
|
tell.send(event)
|
||||||
|
seen.add(user.nick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,7 +231,13 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNickChange(event: NickChangeEvent?) {
|
override fun onNickChange(event: NickChangeEvent?) {
|
||||||
event?.let { tell.send(event) }
|
event?.let {
|
||||||
|
tell.send(event)
|
||||||
|
if (!it.oldNick.equals(it.newNick, true)) {
|
||||||
|
seen.add(it.oldNick)
|
||||||
|
}
|
||||||
|
seen.add(it.newNick)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPart(event: PartEvent?) {
|
override fun onPart(event: PartEvent?) {
|
||||||
|
@ -236,6 +245,7 @@ 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")
|
||||||
|
seen.add(userChannelDao.getChannel(channel).users)
|
||||||
} else {
|
} else {
|
||||||
seen.add(user.nick)
|
seen.add(user.nick)
|
||||||
}
|
}
|
||||||
|
@ -424,10 +434,10 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
|
||||||
addons.add(Ping())
|
addons.add(Ping())
|
||||||
addons.add(RockPaperScissors())
|
addons.add(RockPaperScissors())
|
||||||
addons.add(StockQuote())
|
addons.add(StockQuote())
|
||||||
addons.add(Weather2())
|
|
||||||
addons.add(WorldTime())
|
|
||||||
addons.add(War())
|
addons.add(War())
|
||||||
|
addons.add(Weather2())
|
||||||
addons.add(WolframAlpha())
|
addons.add(WolframAlpha())
|
||||||
|
addons.add(WorldTime())
|
||||||
|
|
||||||
// Sort the addons
|
// Sort the addons
|
||||||
addons.names.sort()
|
addons.names.sort()
|
||||||
|
|
|
@ -214,7 +214,7 @@ object Utils {
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
logger.error("An IO error occurred loading the ${description}.", e)
|
logger.error("An IO error occurred loading the ${description}.", e)
|
||||||
} catch (e: ClassNotFoundException) {
|
} catch (e: ClassNotFoundException) {
|
||||||
logger.error("An error occurred loading the {$description}.", e)
|
logger.error("An error occurred loading the ${description}.", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return default
|
return default
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* SeenComparator.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
|
||||||
|
|
||||||
|
class NickComparator: Comparator<String>, Serializable {
|
||||||
|
override fun compare(a: String, b: String): Int {
|
||||||
|
return a.lowercase().compareTo(b.lowercase())
|
||||||
|
}
|
||||||
|
companion object {
|
||||||
|
private const val serialVersionUID = 1L
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
package net.thauvin.erik.mobibot.commands.seen
|
package net.thauvin.erik.mobibot.commands.seen
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSortedSet
|
||||||
import net.thauvin.erik.mobibot.Utils.bot
|
import net.thauvin.erik.mobibot.Utils.bot
|
||||||
import net.thauvin.erik.mobibot.Utils.helpFormat
|
import net.thauvin.erik.mobibot.Utils.helpFormat
|
||||||
import net.thauvin.erik.mobibot.Utils.loadData
|
import net.thauvin.erik.mobibot.Utils.loadData
|
||||||
|
@ -39,13 +40,16 @@ import net.thauvin.erik.mobibot.Utils.saveData
|
||||||
import net.thauvin.erik.mobibot.Utils.sendMessage
|
import net.thauvin.erik.mobibot.Utils.sendMessage
|
||||||
import net.thauvin.erik.mobibot.commands.AbstractCommand
|
import net.thauvin.erik.mobibot.commands.AbstractCommand
|
||||||
import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime
|
import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime
|
||||||
|
import org.pircbotx.User
|
||||||
import org.pircbotx.hooks.types.GenericMessageEvent
|
import org.pircbotx.hooks.types.GenericMessageEvent
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.util.TreeMap
|
||||||
|
|
||||||
|
|
||||||
class Seen(private val serialObject: String) : AbstractCommand() {
|
class Seen(private val serialObject: String) : AbstractCommand() {
|
||||||
private val logger: Logger = LoggerFactory.getLogger(Seen::class.java)
|
private val logger: Logger = LoggerFactory.getLogger(Seen::class.java)
|
||||||
val seenNicks: MutableList<SeenNick> = mutableListOf()
|
val seenNicks = TreeMap<String, SeenNick>(NickComparator())
|
||||||
|
|
||||||
override val name = "seen"
|
override val name = "seen"
|
||||||
override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name <nick>"))
|
override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name <nick>"))
|
||||||
|
@ -53,6 +57,7 @@ class Seen(private val serialObject: String) : AbstractCommand() {
|
||||||
override val isPublic = true
|
override val isPublic = true
|
||||||
override val isVisible = true
|
override val isVisible = true
|
||||||
|
|
||||||
|
|
||||||
override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
|
override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
|
||||||
if (isEnabled()) {
|
if (isEnabled()) {
|
||||||
if (args.isNotBlank() && !args.contains(' ')) {
|
if (args.isNotBlank() && !args.contains(' ')) {
|
||||||
|
@ -63,12 +68,11 @@ class Seen(private val serialObject: String) : AbstractCommand() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
seenNicks.forEach {
|
if (seenNicks.containsKey(args)) {
|
||||||
if (it.nick.equals(args, true)) {
|
val seenNick = seenNicks.getValue(args)
|
||||||
val lastSeen = System.currentTimeMillis() - it.last
|
val lastSeen = System.currentTimeMillis() - seenNick.lastSeen
|
||||||
event.sendMessage("${it.nick} was last seen on $channel ${lastSeen.toUptime()} ago.")
|
event.sendMessage("${seenNick.nick} was last seen on $channel ${lastSeen.toUptime()} ago.")
|
||||||
return
|
return
|
||||||
}
|
|
||||||
}
|
}
|
||||||
event.sendMessage("I haven't seen $args on $channel lately.")
|
event.sendMessage("I haven't seen $args on $channel lately.")
|
||||||
} else {
|
} else {
|
||||||
|
@ -79,15 +83,16 @@ class Seen(private val serialObject: String) : AbstractCommand() {
|
||||||
|
|
||||||
fun add(nick: String) {
|
fun add(nick: String) {
|
||||||
if (isEnabled()) {
|
if (isEnabled()) {
|
||||||
seenNicks.forEach {
|
seenNicks[nick] = SeenNick(nick, System.currentTimeMillis())
|
||||||
if (it.nick.equals(nick, true)) {
|
save()
|
||||||
if (it.nick != nick) it.nick = nick
|
}
|
||||||
it.last = System.currentTimeMillis()
|
}
|
||||||
save()
|
|
||||||
return
|
fun add(users: ImmutableSortedSet<User>) {
|
||||||
}
|
if (isEnabled()) {
|
||||||
|
users.forEach {
|
||||||
|
seenNicks[it.nick] = SeenNick(it.nick, System.currentTimeMillis())
|
||||||
}
|
}
|
||||||
seenNicks.add(SeenNick(nick))
|
|
||||||
save()
|
save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,12 +104,14 @@ class Seen(private val serialObject: String) : AbstractCommand() {
|
||||||
fun load() {
|
fun load() {
|
||||||
if (isEnabled()) {
|
if (isEnabled()) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
seenNicks += loadData(
|
seenNicks.putAll(
|
||||||
serialObject,
|
loadData(
|
||||||
mutableListOf<SeenNick>(),
|
serialObject,
|
||||||
logger,
|
TreeMap<String, SeenNick>(),
|
||||||
"seen nicknames"
|
logger,
|
||||||
) as MutableList<SeenNick>
|
"seen nicknames"
|
||||||
|
) as TreeMap<String, SeenNick>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ package net.thauvin.erik.mobibot.commands.seen
|
||||||
|
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
data class SeenNick(var nick: String, var last: Long = System.currentTimeMillis()) : Serializable {
|
data class SeenNick(val nick: String, val lastSeen: Long) : Serializable {
|
||||||
companion object {
|
companion object {
|
||||||
private const val serialVersionUID = 1L
|
private const val serialVersionUID = 1L
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ package net.thauvin.erik.mobibot.commands.seen
|
||||||
import assertk.assertThat
|
import assertk.assertThat
|
||||||
import assertk.assertions.isEqualTo
|
import assertk.assertions.isEqualTo
|
||||||
import assertk.assertions.isGreaterThan
|
import assertk.assertions.isGreaterThan
|
||||||
|
import assertk.assertions.isNotEqualTo
|
||||||
import assertk.assertions.isTrue
|
import assertk.assertions.isTrue
|
||||||
import org.testng.annotations.AfterClass
|
import org.testng.annotations.AfterClass
|
||||||
import org.testng.annotations.BeforeClass
|
import org.testng.annotations.BeforeClass
|
||||||
|
@ -45,6 +46,7 @@ import kotlin.io.path.fileSize
|
||||||
class SeenTest {
|
class SeenTest {
|
||||||
private val tmpFile = kotlin.io.path.createTempFile(suffix = ".ser")
|
private val tmpFile = kotlin.io.path.createTempFile(suffix = ".ser")
|
||||||
private val seen = Seen(tmpFile.toAbsolutePath().toString())
|
private val seen = Seen(tmpFile.toAbsolutePath().toString())
|
||||||
|
private val nick = "ErikT"
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
fun saveTest() {
|
fun saveTest() {
|
||||||
|
@ -57,12 +59,21 @@ class SeenTest {
|
||||||
tmpFile.deleteIfExists()
|
tmpFile.deleteIfExists()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(priority = 1)
|
||||||
fun loadTest() {
|
fun loadTest() {
|
||||||
val nick = seen.seenNicks[0]
|
|
||||||
seen.clear()
|
seen.clear()
|
||||||
|
assertThat(seen.seenNicks.isEmpty(), "nicknames map is not empty").isTrue()
|
||||||
seen.load()
|
seen.load()
|
||||||
assertThat(seen.seenNicks[0] == nick, "nick is different").isTrue()
|
assertThat(seen.seenNicks.containsKey(nick), "nick is missing").isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun addTest() {
|
||||||
|
val last = seen.seenNicks[nick]?.lastSeen
|
||||||
|
seen.add(nick.lowercase())
|
||||||
|
assertThat(seen.seenNicks.size, "nick is duplicated").isEqualTo(1)
|
||||||
|
assertThat(seen.seenNicks[nick]?.lastSeen, "last seen is not different").isNotEqualTo(last)
|
||||||
|
assertThat(seen.seenNicks[nick]?.nick, "nick is not lowercase").isEqualTo(nick.lowercase())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(priority = 10)
|
@Test(priority = 10)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#Generated by the Semver Plugin for Gradle
|
#Generated by the Semver Plugin for Gradle
|
||||||
#Fri Sep 16 00:01:57 PDT 2022
|
#Fri Sep 16 10:29:48 PDT 2022
|
||||||
version.buildmeta=525
|
version.buildmeta=542
|
||||||
version.major=0
|
version.major=0
|
||||||
version.minor=8
|
version.minor=8
|
||||||
version.patch=0
|
version.patch=0
|
||||||
version.prerelease=rc
|
version.prerelease=rc
|
||||||
version.project=mobibot
|
version.project=mobibot
|
||||||
version.semver=0.8.0-rc+525
|
version.semver=0.8.0-rc+542
|
||||||
|
|
|
@ -100,7 +100,7 @@
|
||||||
<div><code>mobibot: time UK</code></div>
|
<div><code>mobibot: time UK</code></div>
|
||||||
<div><code>mobibot: time GMT</code></div>
|
<div><code>mobibot: time GMT</code></div>
|
||||||
</li>
|
</li>
|
||||||
<li>Sending messages to people on join/activity:
|
<li>Sending messages to people on join/activity
|
||||||
<div><code>mobibot: tell nickname Give me a call when you see this.</code></div>
|
<div><code>mobibot: tell nickname Give me a call when you see this.</code></div>
|
||||||
</li>
|
</li>
|
||||||
<li>Recapping public channel messages
|
<li>Recapping public channel messages
|
||||||
|
@ -109,6 +109,9 @@
|
||||||
<li>Listing the users on the channel
|
<li>Listing the users on the channel
|
||||||
<div><code>/msg mobibot users</code></div>
|
<div><code>/msg mobibot users</code></div>
|
||||||
</li>
|
</li>
|
||||||
|
<li>Viewing when a nickname was last seen
|
||||||
|
<div><code>/msg mobibot seen nickname</code></div>
|
||||||
|
</li>
|
||||||
<li>Random jokes from <a href="http://www.icndb.com/">The Internet Chuck Norris Database</a>
|
<li>Random jokes from <a href="http://www.icndb.com/">The Internet Chuck Norris Database</a>
|
||||||
<div><code>mobibot: joke</code></div>
|
<div><code>mobibot: joke</code></div>
|
||||||
</li>
|
</li>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue