init
This commit is contained in:
commit
bd9bb0d226
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.connection.json
|
||||
.warehouse/
|
||||
.stack-work/
|
||||
!haskell-basic-irc-bot.cabal
|
||||
*~
|
3
ChangeLog.md
Normal file
3
ChangeLog.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Changelog for haskell-basic-irc-bot
|
||||
|
||||
## Unreleased changes
|
30
LICENSE
Normal file
30
LICENSE
Normal file
@ -0,0 +1,30 @@
|
||||
Copyright Author name here (c) 2019
|
||||
|
||||
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 Author name here nor the names of other
|
||||
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
|
||||
OWNER 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.
|
41
app/Main.hs
Normal file
41
app/Main.hs
Normal file
@ -0,0 +1,41 @@
|
||||
{-# LANGUAGE MultiWayIf #-}
|
||||
|
||||
|
||||
import IrcBot.IrcBot as I
|
||||
import IrcBot.JsonConfigDecoder
|
||||
import qualified Data.ByteString.Lazy as C
|
||||
import Data.Aeson
|
||||
import Data.Maybe
|
||||
import qualified Control.Concurrent as T
|
||||
|
||||
|
||||
|
||||
|
||||
initWithOptions:: Maybe IOptions -> IO()
|
||||
initWithOptions (Just options) = do
|
||||
let serverAddresses = (servers options)
|
||||
mapM (\x -> T.forkIO (I.connectToIRCServer x)) serverAddresses
|
||||
print "[all threads initialized!]"
|
||||
|
||||
initWithOptions _ = print "BAD OPTIONS JSON"
|
||||
|
||||
|
||||
mainLoop :: IO ()
|
||||
mainLoop = do
|
||||
T.threadDelay 1000000
|
||||
mainLoop
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
|
||||
let externalVar = []
|
||||
output <- C.readFile ".connection.json"
|
||||
let options = decode output :: Maybe IOptions
|
||||
-- let servers = decode output :: Maybe IServerAddress
|
||||
initWithOptions options
|
||||
-- let serverAddress = fromJust serverAddressDecoded
|
||||
|
||||
-- mapM (\x -> I.connectToIRCServer x) servers
|
||||
-- I.connectToIRCServer servers
|
||||
mainLoop
|
||||
print "its over"
|
22
example.json
Normal file
22
example.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"servers": [
|
||||
{
|
||||
"server": "irc.freenode.net",
|
||||
"port": 6697,
|
||||
"ssl": true,
|
||||
"nickname": "hBotTest1",
|
||||
"channels": [
|
||||
"#123123123123_test_channel"
|
||||
]
|
||||
},
|
||||
{
|
||||
"server": "irc.freenode.net",
|
||||
"port": 6697,
|
||||
"ssl": true,
|
||||
"nickname": "hBotTest",
|
||||
"channels": [
|
||||
"#123123123123_test_channel1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
88
haskell-basic-irc-bot.cabal
Normal file
88
haskell-basic-irc-bot.cabal
Normal file
@ -0,0 +1,88 @@
|
||||
cabal-version: 1.12
|
||||
|
||||
-- This file has been generated from package.yaml by hpack version 0.31.2.
|
||||
--
|
||||
-- see: https://github.com/sol/hpack
|
||||
--
|
||||
-- hash: 73007a389ec8f6641f20fee7630b2329226a4677d5a1c4a2dfe3c7fcb973f5ad
|
||||
|
||||
name: haskell-basic-irc-bot
|
||||
version: 0.1.0.0
|
||||
description: Please see the README on GitHub at <https://github.com/githubuser/haskell-basic-irc-bot#readme>
|
||||
homepage: https://github.com/githubuser/haskell-basic-irc-bot#readme
|
||||
bug-reports: https://github.com/githubuser/haskell-basic-irc-bot/issues
|
||||
author: Author name here
|
||||
maintainer: example@example.com
|
||||
copyright: 2019 Author name here
|
||||
license: BSD3
|
||||
license-file: LICENSE
|
||||
build-type: Simple
|
||||
extra-source-files:
|
||||
README.md
|
||||
ChangeLog.md
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
location: https://github.com/githubuser/haskell-basic-irc-bot
|
||||
|
||||
library
|
||||
exposed-modules:
|
||||
IrcBot.BotNetwork
|
||||
, IrcBot.BotNetworkCommands
|
||||
, IrcBot.JsonConfigDecoder
|
||||
, IrcBot.BotActions
|
||||
, IrcBot.MessageParser
|
||||
, IrcBot.RemoteUploader
|
||||
, IrcBot.IrcBot
|
||||
, IrcBot.RandomFileFinder
|
||||
, IrcBot.BotCustomCommands
|
||||
other-modules:
|
||||
Paths_haskell_basic_irc_bot
|
||||
hs-source-dirs:
|
||||
src
|
||||
build-depends:
|
||||
base >=4.7 && <5
|
||||
, network
|
||||
, bytestring
|
||||
, text
|
||||
, process
|
||||
, directory
|
||||
, random
|
||||
, connection
|
||||
, json
|
||||
, aeson
|
||||
, MissingH
|
||||
default-language: Haskell2010
|
||||
|
||||
executable haskell-basic-irc-bot-exe
|
||||
main-is: Main.hs
|
||||
other-modules:
|
||||
Paths_haskell_basic_irc_bot
|
||||
hs-source-dirs:
|
||||
app
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends:
|
||||
base >=4.7 && <5
|
||||
, haskell-basic-irc-bot
|
||||
, network
|
||||
, bytestring
|
||||
, text
|
||||
, process
|
||||
, random
|
||||
, connection
|
||||
, json
|
||||
, aeson
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite haskell-basic-irc-bot-test
|
||||
type: exitcode-stdio-1.0
|
||||
main-is: Spec.hs
|
||||
other-modules:
|
||||
Paths_haskell_basic_irc_bot
|
||||
hs-source-dirs:
|
||||
test
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends:
|
||||
base >=4.7 && <5
|
||||
, haskell-basic-irc-bot
|
||||
default-language: Haskell2010
|
48
package.yaml
Normal file
48
package.yaml
Normal file
@ -0,0 +1,48 @@
|
||||
name: haskell-basic-irc-bot
|
||||
version: 0.1.0.0
|
||||
github: "githubuser/haskell-basic-irc-bot"
|
||||
license: BSD3
|
||||
author: "Author name here"
|
||||
maintainer: "example@example.com"
|
||||
copyright: "2019 Author name here"
|
||||
|
||||
extra-source-files:
|
||||
- README.md
|
||||
- ChangeLog.md
|
||||
|
||||
# Metadata used when publishing your package
|
||||
# synopsis: Short description of your package
|
||||
# category: Web
|
||||
|
||||
# To avoid duplicated efforts in documentation and dealing with the
|
||||
# complications of embedding Haddock markup inside cabal files, it is
|
||||
# common to point users to the README.md file.
|
||||
description: Please see the README on GitHub at <https://github.com/githubuser/haskell-basic-irc-bot#readme>
|
||||
|
||||
dependencies:
|
||||
- base >= 4.7 && < 5
|
||||
|
||||
library:
|
||||
source-dirs: src
|
||||
|
||||
executables:
|
||||
haskell-basic-irc-bot-exe:
|
||||
main: Main.hs
|
||||
source-dirs: app
|
||||
ghc-options:
|
||||
- -threaded
|
||||
- -rtsopts
|
||||
- -with-rtsopts=-N
|
||||
dependencies:
|
||||
- haskell-basic-irc-bot
|
||||
|
||||
tests:
|
||||
haskell-basic-irc-bot-test:
|
||||
main: Spec.hs
|
||||
source-dirs: test
|
||||
ghc-options:
|
||||
- -threaded
|
||||
- -rtsopts
|
||||
- -with-rtsopts=-N
|
||||
dependencies:
|
||||
- haskell-basic-irc-bot
|
63
src/IrcBot/BotActions.hs
Normal file
63
src/IrcBot/BotActions.hs
Normal file
@ -0,0 +1,63 @@
|
||||
{-# LANGUAGE MultiWayIf #-}
|
||||
|
||||
module IrcBot.BotActions where
|
||||
|
||||
|
||||
import Network.Connection
|
||||
import Network.Socket hiding (send, sendTo, recv, recvFrom)
|
||||
import qualified Data.ByteString.Char8 as C
|
||||
import IrcBot.BotNetwork
|
||||
import IrcBot.BotNetworkCommands
|
||||
import IrcBot.MessageParser
|
||||
import IrcBot.BotCustomCommands
|
||||
|
||||
messageParse:: Connection -> C.ByteString -> IO()
|
||||
|
||||
|
||||
-- its kind of interface for actionFunctions
|
||||
callActionFunction :: (IServerResponse -> IO()) -> IServerResponse -> IO ()
|
||||
callActionFunction myFunc parameter1 = myFunc parameter1
|
||||
|
||||
|
||||
messageParse sock stringData =
|
||||
do
|
||||
let unpackedByteString = C.unpack stringData
|
||||
let debugData = "READ DATA FROM SOCKET: " ++ unpackedByteString
|
||||
let userNick = parseNick unpackedByteString
|
||||
let channelName = parseChannelName unpackedByteString
|
||||
let messageText = parseMessageText unpackedByteString
|
||||
let newServerResponse = IServerResponse {
|
||||
readDataString = unpackedByteString,
|
||||
readDataByteString = stringData,
|
||||
sock = sock,
|
||||
channelName = channelName,
|
||||
nick = userNick,
|
||||
messageText = messageText
|
||||
}
|
||||
mapM (\x -> callActionFunction (x) newServerResponse) (methods myMethodList)
|
||||
let d = "PARSE PURSE MESASGE: " ++ messageText
|
||||
print d
|
||||
print debugData
|
||||
-- if | hasStringExist "PING " stringData -> pong sock unpackedByteString
|
||||
-- | hasStringExist ".sup" stringData -> sendMessage sock channelName ("sup " ++ userNick)
|
||||
-- | hasStringExist " KICK #" stringData -> joinChannel sock channelName >> {-- auto connect in case of kick --} sendMessage sock channelName "fuck you"
|
||||
-- | hasStringExist ".random" stringData -> basicRandomImplementation unpackedByteString >>= \commandOutput -> sendMessage sock channelName commandOutput
|
||||
-- | hasStringExist ".quit" stringData -> quitFromServer sock channelName
|
||||
-- | hasStringExist ".leave" stringData -> disconnectFromChannel sock channelName
|
||||
-- | otherwise -> print "NO CONDITION FOUND TO PARSE"
|
||||
|
||||
connectToServer :: String -> PortNumber -> Bool -> IO Connection
|
||||
connectToServer server port ssl = do
|
||||
open server port ssl
|
||||
|
||||
connectionLoop :: Connection -> IO Connection
|
||||
connectionLoop sock =
|
||||
do
|
||||
stringData <- readFromSocket sock
|
||||
messageParse sock stringData
|
||||
case stringData == C.empty of
|
||||
False -> do
|
||||
connectionLoop sock
|
||||
True -> do
|
||||
return sock
|
||||
|
72
src/IrcBot/BotCustomCommands.hs
Normal file
72
src/IrcBot/BotCustomCommands.hs
Normal file
@ -0,0 +1,72 @@
|
||||
{-# LANGUAGE MultiWayIf #-}
|
||||
|
||||
module IrcBot.BotCustomCommands where
|
||||
|
||||
import Network.Connection
|
||||
import qualified Data.ByteString.Char8 as C
|
||||
import IrcBot.BotNetwork
|
||||
import IrcBot.BotNetworkCommands
|
||||
import IrcBot.MessageParser
|
||||
|
||||
data IServerResponse = IServerResponse
|
||||
{
|
||||
readDataString :: String,
|
||||
readDataByteString :: C.ByteString,
|
||||
sock :: Connection,
|
||||
channelName :: String,
|
||||
nick :: String,
|
||||
messageText :: String
|
||||
}
|
||||
|
||||
data MethodList = MethodList { methods :: [IServerResponse -> IO()]}
|
||||
|
||||
|
||||
|
||||
hasStringExist:: String -> C.ByteString -> Bool
|
||||
hasStringExist search source =
|
||||
do
|
||||
let byteStringSearch = C.pack search
|
||||
C.isInfixOf byteStringSearch source
|
||||
|
||||
|
||||
|
||||
basicEcho :: IServerResponse -> IO ()
|
||||
basicEcho serverResponse = do
|
||||
if | hasStringExist ".echo" (readDataByteString serverResponse) -> sendMessage (sock serverResponse) (channelName serverResponse) "EXAMPLE MESSAGE"
|
||||
| otherwise -> print "NO CONDITION FOUND TO PARSE"
|
||||
|
||||
|
||||
ping :: IServerResponse -> IO ()
|
||||
ping serverResponse = do
|
||||
if | hasStringExist "PING " (readDataByteString serverResponse) -> pong (sock serverResponse) (readDataString serverResponse)
|
||||
| otherwise -> print "NO CONDITION FOUND TO PARSE"
|
||||
|
||||
|
||||
|
||||
autoconnect :: IServerResponse -> IO ()
|
||||
autoconnect serverResponse = do
|
||||
if | hasStringExist " KICK #" (readDataByteString serverResponse) -> joinChannel (sock serverResponse) (channelName serverResponse) >> {-- auto connect in case of kick --} sendMessage (sock serverResponse) (channelName serverResponse) "automated rejoin, if you want me to leave use .leave"
|
||||
| otherwise -> print "NO CONDITION FOUND TO PARSE"
|
||||
|
||||
|
||||
randomImage :: IServerResponse -> IO ()
|
||||
randomImage serverResponse = do
|
||||
if | hasStringExist ".random" (readDataByteString serverResponse) -> basicRandomImplementation (readDataString serverResponse) >>= \commandOutput -> sendMessage (sock serverResponse) (channelName serverResponse) commandOutput
|
||||
| otherwise -> print "NO CONDITION FOUND TO PARSE"
|
||||
|
||||
|
||||
quit :: IServerResponse -> IO ()
|
||||
quit serverResponse = do
|
||||
if | hasStringExist ".quit" (readDataByteString serverResponse) -> quitFromServer (sock serverResponse) (channelName serverResponse)
|
||||
| otherwise -> print "NO CONDITION FOUND TO PARSE"
|
||||
|
||||
|
||||
|
||||
leave :: IServerResponse -> IO ()
|
||||
leave serverResponse = do
|
||||
if | hasStringExist ".leave" (readDataByteString serverResponse) -> disconnectFromChannel (sock serverResponse) (channelName serverResponse)
|
||||
| otherwise -> print "NO CONDITION FOUND TO PARSE"
|
||||
|
||||
|
||||
|
||||
myMethodList = MethodList {methods = [basicEcho, ping, autoconnect, randomImage, quit, leave] }
|
49
src/IrcBot/BotNetwork.hs
Normal file
49
src/IrcBot/BotNetwork.hs
Normal file
@ -0,0 +1,49 @@
|
||||
{-# LANGUAGE MultiWayIf #-}
|
||||
|
||||
module IrcBot.BotNetwork where
|
||||
|
||||
import Network.Socket hiding (send, sendTo, recv, recvFrom)
|
||||
import Network.Socket.ByteString (recv, sendAll)
|
||||
import qualified Data.ByteString.Char8 as C
|
||||
import Network.Connection
|
||||
|
||||
readFromSocket:: Connection -> IO C.ByteString
|
||||
writeToSocket:: Connection -> String -> IO()
|
||||
|
||||
|
||||
writeToSocket sock stringData =
|
||||
do
|
||||
let socketString = stringData ++ "\n"
|
||||
let byteStringDataConverter = C.pack socketString
|
||||
connectionPut sock byteStringDataConverter
|
||||
print "SENT DATA IS: "
|
||||
print byteStringDataConverter
|
||||
|
||||
readFromSocket sock =
|
||||
do
|
||||
msg <- connectionGet sock 1024
|
||||
case msg == C.empty of
|
||||
False -> do
|
||||
return msg
|
||||
True -> do
|
||||
return C.empty
|
||||
|
||||
|
||||
open:: String -> PortNumber -> Bool -> IO Connection
|
||||
|
||||
open server port ssl = do
|
||||
ctx <- initConnectionContext
|
||||
-- sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
|
||||
print "CONNECTING"
|
||||
ctx <- initConnectionContext
|
||||
con <- connectTo ctx $ ConnectionParams
|
||||
{ connectionHostname = server
|
||||
, connectionPort = port
|
||||
, connectionUseSecure = case ssl of
|
||||
True -> Just $ Network.Connection.TLSSettingsSimple False False True
|
||||
False -> Nothing
|
||||
, connectionUseSocks = Nothing
|
||||
}
|
||||
print "CONNECTED"
|
||||
return con
|
||||
|
59
src/IrcBot/BotNetworkCommands.hs
Normal file
59
src/IrcBot/BotNetworkCommands.hs
Normal file
@ -0,0 +1,59 @@
|
||||
module IrcBot.BotNetworkCommands where
|
||||
|
||||
import IrcBot.BotNetwork (writeToSocket)
|
||||
import Network.Socket hiding (send, sendTo, recv, recvFrom)
|
||||
import Network.Connection
|
||||
import Data.List.Utils (replace)
|
||||
|
||||
sendMessage :: Connection -> String -> String -> IO ()
|
||||
|
||||
sendMessage sock targetChannel stringData =
|
||||
do
|
||||
let combiendStringData = "PRIVMSG " ++ targetChannel ++ " :" ++ stringData
|
||||
writeToSocket sock combiendStringData
|
||||
|
||||
|
||||
|
||||
quitFromServer :: Connection -> String -> IO ()
|
||||
|
||||
quitFromServer sock targetChannel =
|
||||
do
|
||||
writeToSocket sock "QUIT"
|
||||
|
||||
disconnectFromChannel :: Connection -> String -> IO ()
|
||||
|
||||
disconnectFromChannel sock targetChannel =
|
||||
do
|
||||
writeToSocket sock ("PART " ++ targetChannel)
|
||||
|
||||
|
||||
|
||||
initBotName :: Connection -> String -> IO ()
|
||||
|
||||
initBotName sock botName =
|
||||
do
|
||||
let dataString = "USER "++ botName ++" "++ botName ++" "++ botName ++" :learning purpose bot"
|
||||
writeToSocket sock dataString
|
||||
|
||||
|
||||
initBotNick :: Connection -> String -> IO ()
|
||||
|
||||
initBotNick sock botNick =
|
||||
do
|
||||
let nick = "NICK " ++ botNick
|
||||
writeToSocket sock nick
|
||||
|
||||
|
||||
joinChannel :: Connection -> String -> IO ()
|
||||
|
||||
joinChannel sock channelName =
|
||||
do
|
||||
let combinedString = "JOIN " ++ channelName
|
||||
writeToSocket sock combinedString
|
||||
|
||||
|
||||
pong :: Connection -> String -> IO ()
|
||||
|
||||
pong sock receivedStringData = do
|
||||
let replacedText = replace "PING" "PONG" receivedStringData
|
||||
writeToSocket sock replacedText
|
45
src/IrcBot/IrcBot.hs
Normal file
45
src/IrcBot/IrcBot.hs
Normal file
@ -0,0 +1,45 @@
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
|
||||
module IrcBot.IrcBot where
|
||||
|
||||
import Network.Socket
|
||||
import IrcBot.BotNetworkCommands
|
||||
import IrcBot.BotActions
|
||||
import IrcBot.BotNetwork
|
||||
import Network.Connection
|
||||
import qualified Control.Concurrent as T
|
||||
import qualified Data.ByteString.Char8 as C
|
||||
|
||||
data IServerAddress = IServerAddress
|
||||
{
|
||||
server :: String ,
|
||||
port :: Int,
|
||||
ssl :: Bool,
|
||||
nickname :: String,
|
||||
channels :: [String]
|
||||
} deriving (Show)
|
||||
|
||||
data IOptions = IOptions
|
||||
{
|
||||
servers :: [Maybe IServerAddress]
|
||||
} deriving (Show)
|
||||
|
||||
|
||||
|
||||
|
||||
connectToIRCServer :: Maybe IServerAddress -> IO ()
|
||||
connectToIRCServer (Just serverAddress) = do
|
||||
newSock <- connectToServer (server serverAddress) (fromIntegral (port serverAddress)) (ssl serverAddress)
|
||||
print "[connected to server]"
|
||||
initBotName newSock (nickname serverAddress)
|
||||
initBotNick newSock (nickname serverAddress)
|
||||
let channelsToJoin = channels serverAddress
|
||||
mapM (\x -> joinChannel newSock x) channelsToJoin
|
||||
connectionLoop newSock
|
||||
print "sleeping 15 sec for reconnect"
|
||||
-- 1000000 is 1 second
|
||||
T.threadDelay (1000000 * 15)
|
||||
print "reconnecting sequence initializing"
|
||||
-- this is a recursive function and its maintaining own connectivity
|
||||
-- how deep can i call this function? or just compiler optimizes for me? no idea
|
||||
connectToIRCServer (Just serverAddress)
|
35
src/IrcBot/JsonConfigDecoder.hs
Normal file
35
src/IrcBot/JsonConfigDecoder.hs
Normal file
@ -0,0 +1,35 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module IrcBot.JsonConfigDecoder where
|
||||
|
||||
import Data.Aeson
|
||||
import Network.Socket
|
||||
import IrcBot.IrcBot
|
||||
import qualified Data.ByteString.Lazy as C
|
||||
|
||||
|
||||
instance FromJSON IServerAddress where
|
||||
parseJSON = withObject "IServerAddress" $ \o -> do
|
||||
server_ <- o .: "server"
|
||||
port_ <- o .: "port"
|
||||
ssl_ <- o .: "ssl"
|
||||
nickname_ <- o .: "nickname"
|
||||
channels_ <- o .: "channels"
|
||||
return $ IServerAddress server_ port_ ssl_ nickname_ channels_
|
||||
|
||||
|
||||
instance FromJSON IOptions where
|
||||
parseJSON = withObject "IOptions" $ \o -> do
|
||||
servers_ <- o .: "servers"
|
||||
return $ IOptions servers_
|
||||
|
||||
|
||||
--readConfigFile :: Maybe IServerAddress
|
||||
--readConfigFile = C.readFile ".connection.json" >>= \output -> decode output :: Maybe IServerAddress
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
51
src/IrcBot/MessageParser.hs
Normal file
51
src/IrcBot/MessageParser.hs
Normal file
@ -0,0 +1,51 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
module IrcBot.MessageParser where
|
||||
|
||||
import Data.List
|
||||
import Data.Maybe
|
||||
import IrcBot.RandomFileFinder
|
||||
import IrcBot.RemoteUploader
|
||||
|
||||
getNthElementFromString :: String -> Int -> Char
|
||||
getNthElementFromString stringData step = stringData !! step
|
||||
|
||||
|
||||
|
||||
|
||||
slice :: Int -> Int -> String -> String
|
||||
slice start end = take (end-start-1) . drop (start+1)
|
||||
|
||||
|
||||
|
||||
-- :YOUR_NICK!~YOUR_NICK@YOUR_IP PRIVMSG #91623_my_test_channel
|
||||
|
||||
parseNick :: String -> String
|
||||
|
||||
parseNick dataString =
|
||||
do
|
||||
let startIndex = elemIndex ':' dataString
|
||||
let endIndex = elemIndex '!' dataString
|
||||
slice (fromJust startIndex) (fromJust endIndex) dataString
|
||||
|
||||
parseChannelName :: String -> String
|
||||
|
||||
parseChannelName dataString =
|
||||
do
|
||||
let startIndex = elemIndex '#' dataString
|
||||
let dropppedString = drop (fromJust startIndex) dataString
|
||||
let endIndex = elemIndex ' ' dropppedString
|
||||
take (fromJust endIndex) dropppedString
|
||||
|
||||
|
||||
|
||||
parseMessageText :: String -> String
|
||||
parseMessageText dataString =
|
||||
do
|
||||
(drop 1 (unwords (drop 3 (words dataString))))
|
||||
|
||||
|
||||
|
||||
|
||||
basicRandomImplementation :: String -> IO String
|
||||
|
||||
basicRandomImplementation basicInput = getRandomFile "maidos" >>= \randomFileName -> uploadLocalFile randomFileName
|
18
src/IrcBot/RandomFileFinder.hs
Normal file
18
src/IrcBot/RandomFileFinder.hs
Normal file
@ -0,0 +1,18 @@
|
||||
module IrcBot.RandomFileFinder where
|
||||
|
||||
import System.Directory
|
||||
import System.Random
|
||||
|
||||
|
||||
|
||||
getRandomFile :: String -> IO String
|
||||
|
||||
|
||||
getRandomFile directoryName =
|
||||
do
|
||||
let fullDirectoryName = "./.warehouse/" ++ directoryName
|
||||
directoryItems <- getDirectoryContents fullDirectoryName
|
||||
result <- return (length directoryItems) >>= \count -> randomRIO(4,count) :: IO Int
|
||||
let fileName = directoryItems !! result
|
||||
let newFileName = ".warehouse/" ++ directoryName ++ "/" ++ fileName
|
||||
return newFileName
|
14
src/IrcBot/RemoteUploader.hs
Normal file
14
src/IrcBot/RemoteUploader.hs
Normal file
@ -0,0 +1,14 @@
|
||||
module IrcBot.RemoteUploader where
|
||||
|
||||
|
||||
import System.Process
|
||||
|
||||
|
||||
uploadLocalFile:: String -> IO String
|
||||
|
||||
uploadLocalFile filePath =
|
||||
do
|
||||
let command = "curl"
|
||||
let params = "file=@"++ filePath
|
||||
readProcess command ["-F",params,"0x0.st"] ""
|
||||
|
64
stack.yaml
Normal file
64
stack.yaml
Normal file
@ -0,0 +1,64 @@
|
||||
# This file was automatically generated by 'stack init'
|
||||
#
|
||||
# Some commonly used options have been documented as comments in this file.
|
||||
# For advanced use and comprehensive documentation of the format, please see:
|
||||
# https://docs.haskellstack.org/en/stable/yaml_configuration/
|
||||
|
||||
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
|
||||
# A snapshot resolver dictates the compiler version and the set of packages
|
||||
# to be used for project dependencies. For example:
|
||||
#
|
||||
# resolver: lts-3.5
|
||||
# resolver: nightly-2015-09-21
|
||||
# resolver: ghc-7.10.2
|
||||
#
|
||||
# The location of a snapshot can be provided as a file or url. Stack assumes
|
||||
# a snapshot provided as a file might change, whereas a url resource does not.
|
||||
#
|
||||
# resolver: ./custom-snapshot.yaml
|
||||
# resolver: https://example.com/snapshots/2018-01-01.yaml
|
||||
resolver: lts-13.28
|
||||
|
||||
# User packages to be built.
|
||||
# Various formats can be used as shown in the example below.
|
||||
#
|
||||
# packages:
|
||||
# - some-directory
|
||||
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||
# - location:
|
||||
# git: https://github.com/commercialhaskell/stack.git
|
||||
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# subdirs:
|
||||
# - auto-update
|
||||
# - wai
|
||||
packages:
|
||||
- .
|
||||
# Dependency packages to be pulled from upstream that are not in the resolver
|
||||
# using the same syntax as the packages field.
|
||||
# (e.g., acme-missiles-0.3)
|
||||
# extra-deps: []
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
# flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
# extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
#
|
||||
# Require a specific version of stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: ">=1.9"
|
||||
#
|
||||
# Override the architecture used by stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
#
|
||||
# Extra directories used by stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
||||
#
|
||||
# Allow a newer minor version of GHC than the snapshot specifies
|
||||
# compiler-check: newer-minor
|
12
stack.yaml.lock
Normal file
12
stack.yaml.lock
Normal file
@ -0,0 +1,12 @@
|
||||
# This file was autogenerated by Stack.
|
||||
# You should not edit this file by hand.
|
||||
# For more information, please see the documentation at:
|
||||
# https://docs.haskellstack.org/en/stable/lock_files
|
||||
|
||||
packages: []
|
||||
snapshots:
|
||||
- completed:
|
||||
size: 500539
|
||||
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/13/28.yaml
|
||||
sha256: cdde1bfb38fdee21c6acb73d506e78f7e12e0a73892adbbbe56374ebef4d3adf
|
||||
original: lts-13.28
|
2
test/Spec.hs
Normal file
2
test/Spec.hs
Normal file
@ -0,0 +1,2 @@
|
||||
main :: IO ()
|
||||
main = putStrLn "Test suite not yet implemented"
|
Loading…
Reference in New Issue
Block a user