aboutsummaryrefslogtreecommitdiffstats
path: root/src/IRC.hs
AgeCommit message (Collapse)Author
2017-11-19Lib: Test application of Bot readerTeddy Wing
A test to try to get _something_ to compile. And it does! Here we try to run a plugin with `runReaderT` and `runBot` to pass `Options` to the plugin, using the "help" plugin as an example. It feeds hard-coded `Options` to the plugin and outputs its response to STDOUT. Also get an implementation of `initializePlugins` working that will allow us to build a list of plugins with `Options` applied to the reader. This commit comments out the whole of IRC.hs in order to get the code to compile. That file still has a bunch of `Bot` monad-related type errors. To build the final plugin list, I think what we'll want to do is use something like `initializePlugins` in Lib to apply all our plugins with the `Options` and then feed that to `connectIRC`. In order to build the "help" plugin, the plan is to re-apply the `Options` after `ask`ing for them inside the `PluginAction` for "help" to all plugins, thus enabling us to get a plugin list with the applied reader for proper localisation of the help output.
2017-11-19Bot(privmsgFromPlugin): Try to use the `Bot` monad instead of `IO`Teddy Wing
Convert this function and `Plugins(performPlugin)` to use a `Bot`-wrapped plugin. Still having a lot of trouble with this, unable to get past monad-related compilation errors. The plan is to leave this as-is for now and attack the problem from a different place, looking at the `main` function next, applying our plugins with `runBot`, and then passing those monad-wrapped plugins to `connectIRC`. Once that's taken care of, we'll see what we need to modify in this middle strata of the stack.
2017-08-27privmsgFromPlugin: Rewrite using MaybeT monad transformerTeddy Wing
OMG it works!!! This took me a week of off-and-on tinkering, learning, procrastinating, and struggling. So awesome that it's finally working! The `liftMaybe` was key, learned that from: https://stackoverflow.com/questions/8684252/how-to-inject-a-maybe-value-into-maybet This article on monad transformers by 'kqr' also helped quite a bit: https://github.com/kqr/gists/blob/master/articles/gentle-introduction-monad-transformers.md A Wikibooks article on the same was somewhat useful: https://en.wikibooks.org/wiki/Haskell/Monad_transformers And this was an interesting look at Alternatives, which I didn't end up using but was interesting nonetheless: http://www.parsonsmatt.org/2016/11/18/clean_alternatives_with_maybet.html When I learned about monad transformers I thought: "Yes! This is what I need to clean up the `privmsgFromPlugin` function.". I wasn't liking the nested `case` statements there, and since everything was a `Maybe`, I thought, why can't we chain the `Maybe`s like we're supposed to be able to with monads? Well, turns out we can. It just involved a lot of tricky `lift`ing. This gets rid of the nesting, resulting in a much cleaner- looking function. So cool!
2017-08-20IRC: Only require "sorbot: " prefix in channelsTeddy Wing
When talking with the bot in a private one-to-one query, there's no reason to use the "sorbot: " prefix because you're not talking to anyone else. In that case, just behave like we did before and allow users to send commands with no prefix.
2017-08-20IRC: Only respond to messages if prefixed with "sorbot: "Teddy Wing
Prevent Sorbot from responding to general messages. Messages must be directed at Sorbot to invoke plugins and get a response.
2017-08-20IRC: Send private messages when plugin is `queryOnly`Teddy Wing
If the plugin is defined as `queryOnly`, the response shouldn't be sent on the channel to everyone, it should instead be sent directly to the user in a private query message. Enable this functionality for the Help plugin so that help output only gets sent to the user requesting help. This ensures other channel participants don't get an annoyingly long section of output that they didn't ask for.
2017-08-20IRC: Speed up message transferTeddy Wing
Instead of waiting 1 second between posting messages, pause 0.2 seconds for faster posting. This may cause flood concerns, but improves responsiveness from commands that send multi-line responses, like Help and Factorial.
2017-08-20IRC: Chop messages longer than 400 charactersTeddy Wing
The IRC protocol doesn't permit messages longer than 512 bytes (https://news.ycombinator.com/item?id=7991049). This includes server, channel, hostname, etc. information that's also included in the message. In order to be able to send longer messages, chop them at 400 characters (https://wholok.com/irc/), which seems like a "reasonable" hard-coded value. We already split our messages at newlines, so we need to effectuate a double split here. First we split at 400 characters because we might have a line that runs longer than that before encountering a newline. To do this, we use the `chunksOf` function (https://wiki.haskell.org/Data.List.Split). Then, when splitting on newlines, we take the list produced by splitting at 400 characters, and must split the elements inside that list. This creates a two-dimensional array. In order to flatten the array, we use the `concat` function (https://stackoverflow.com/questions/5994051/is-there-a-function-to-flatten-a-nested-list-of-elements).
2017-08-20Reformat Help outputTeddy Wing
Instead of printing all help text on a single line as a result of joining the list of help text, print each plugin's help on a separate line. Also separate commands from descriptions with a dash instead of a tab as the tab character was getting rendered as an `I` in irssi instead of the actual whitespace I had been hoping for. The dash in inspired by Hubot. In order to print multiple lines of output, we needed to change the IRC PRIVMSG handler. This now splits the plugin result at newlines into a list and sends separate PRIVMSGs for each line of output. Before, text with newlines would only show the first line in the resulting IRC message. Assume plugin error messages will always be a single line.
2017-08-19IRC.hs: Reformat record update syntaxTeddy Wing
Previously I had moved the `{` to the previous line because I was getting compilation errors with it on a new line. Turns out whitespace is important here. We just need to indent it an extra time and the compiler understands us. Now this section matches the style of the rest of the project.
2017-08-17Change `Plugin` and `Message` from `String` to `Data.Text`Teddy Wing
Use the `Data.Text` type instead of `String` in most of the places we use it in `Plugin` and `Message`. This allows us to more easily pass data between the IRC package. No more kludgy `pack`s and `unpack`s in our IRC message handler. The one thing we couldn't convert was our regex. From what I understand (https://stackoverflow.com/questions/14922579/haskell-regular-expressions-and-data-text#14922626), the regex library I'm using doesn't support `Data.Text`, so use `String`s for that instead.
2017-08-16handlePrivmsg: call out to plugins in QUERYTeddy Wing
When a PRIVMSG comes in from an individual user instead of a channel, invoke our plugins so we're doing the same thing in both cases.
2017-08-16IRC.hs: Remove old commented codeTeddy Wing
This was there as a test but didn't work. It's no longer needed, so we can remove it.
2017-08-16IRC.hs: Handle `Nothing` branchesTeddy Wing
Handle our un-handled `Nothing` branches. Make `privmsgFromPlugin` return a `Maybe` so we can decide whether or not to send a message upstream. If we do get a `Nothing` from `privmsgFromPlugin`, just return unit and don't send any chat message, since no plugin matched and thus none could respond.
2017-08-16handlePrivmsg: Move duplicated code to new functionTeddy Wing
We have some code that's duplicated in both branches of the `Either` case statement that sends a response over IRC. Extract that to a new function that can be shared between the two case statements to try to reduce repetition. Took me a while to wrangle the monads to get this, but it's in working condition now. Need to add the commented `Nothing` branch in so I'm handling all the cases.
2017-08-16Remove commented code from a0d21d9aed3a38e98e622fbae5fcab3e91c5ddeeTeddy Wing
I had a bunch of code commented from earlier and from false starts when working on integrating my plugins and the IRC message handler. Remove these commented lines now as they are no longer relevant. The actual code is functioning.
2017-08-16Connect plugins to IRCTeddy Wing
Instead of sending a hard-coded string message over IRC, now invoke our plugin list. Now, IRC messages get matched against our plugin list, and if any plugin matches, its return string gets posted to the appropriate channel. Move the database connection inside the plugin so that we can continue to access it without having to pass in the DB connection. I didn't want to connect to the database in the IRC code because it doesn't relate, and I don't have a good enough grasp of monads to know if I can create the connection in "Lib.hs" and "pass" it to the IRC message handler to then pass it into the plugins. Moving the database connection inside the plugins means that it no longer takes a database connection as an argument. The IRC message handler now has a lot of duplication, but it basically works, which is super exciting! Took a _long_ time to figure out the proper way to get the types to line up and get this compiling, but really glad it's working now! The magic function turned out to be `liftIO` to extract the `Either String String` out of its `IO` monad wrapper to be fed to the `IRC.send` function. Not a fan of the type conversion between `String` and `Data.Text`, so we'll eventually have to convert our plugins to use `Data.Text`.
2017-08-13Lib.hs: Move IRC-related code to a new "IRC" moduleTeddy Wing
Now that we have something sort of working on the IRC side of things, we can move it out into its own module to keep `Lib` clear and tidy.