Git Product home page Git Product logo

irc-client's Introduction

This project is essentially abandonware!

I may respond to minor issues, like version bounds which need changing, but I won't be doing any significant work.

Offer to take over the package if you want any significant changes.

An IRC client library.

  • Built on irc-conduit.

  • Handles a connection to a single IRC server.

  • Manages "event handlers", calling them as appropriate on receipt of messages.

  • Provides default event handlers for some common messages (e.g., server PINGs).

  • Executes each event handler in its own thread, and uses a message queue to guarantee thread-safe message delivery.

  • Provides a few helper functions for common operations.

Note

This used to be a part of yukibot, so if you want the history from before this was split out into its own library, check there.

Contributing

Bug reports, pull requests, and comments are very welcome!

Feel free to contact me on GitHub, through IRC (#haskell on libera.chat), or email ([email protected]).

irc-client's People

Contributors

barrucadu avatar bazukas avatar dependabot[bot] avatar foollbar avatar geekingfrog avatar jange avatar jmazon avatar k00mi avatar kaizoku avatar liyang avatar myshoggoth avatar tristancacqueray avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

irc-client's Issues

Racey deadlock in disconnect

09:18 <ij> Hey Mike! I'm experimenting with swapping _func of ConnectionConfig to my "client", which just wraps yours but gives me the connection socket also, but it deadlocks 
           before it does anything. Do you have any off the top of head reasons why? http://sprunge.us/PTZX
09:27 <barrucadu> Nothing looks like it should deadlock there, how are you using that?
09:32 <ij> diff + full code, put together: http://sprunge.us/LaGE?diff 
09:32 <ij> Version before the diff works.
09:50 <barrucadu> Are you sure your ircClientTCP is correct?
09:51 <ij> I'll write test code now, but (unsurprisingly) I can't imagine why not.
09:51 <barrucadu> heh
09:52 <ij> The whole code is here in case you want to take a peak: https://github.com/siers/zn/tree/feature/seamless-restart 
09:57 <barrucadu> I think I see the problem
09:59 <barrucadu> runTCPClient in streaming-commons closes the connection when the inner action terminates, so there are two issues: any socket you get out of it is useless, and 
                  ircWithConn is being given a ((AppData -> IO ()) -> IO ()) function operating on a closed socket, which will immediately fail in some way (I'm not sure exactly 
                  how)
10:00 <barrucadu> This then causes a race condition with initialise and disconnect: initialise will set the connection state to Connected, which will make disconnect wait for the 
                  TBMQueue to be empty of messages before closing
10:01 <barrucadu> The queue gets the USER message inserted into it
10:01 <barrucadu> But this can never be sent, because the socket is closed
10:01 <barrucadu> Because the socket is closed, the conduits both die. So no thread other than the main one has a reference to the queue
10:01 <barrucadu> And the main thread is blocked on the queue
10:01 <barrucadu> So it's a deadlock!
10:02 <barrucadu> This is an interesting edge case, I'm not sure how best to handle it
10:03 <barrucadu> Can't wait for the server to send anything to confirm the connection is alive, because nothing gets sent until after the USER message

To summarise: disconnect will deadlock here if the sending conduit dies while there are still messages in the queue. Probably a disconnect timeout is worth adding here, which will just stop waiting for messages to be sent after a while.

Cannot connect to servers with bad TLS configs - provide more options to connectWithTLS function

I'm looking to use this library to connect to a friends server which unfortunately has a slightly broken TLS setup, but mandates TLS for all clients. On my desktop client (weechat), I can just set ssl_verify = off in my config, but there's no way to set options such as this with irc-client.

Would it be possible to expose more connection options to the user?

At present, trying to connect to a server with a bad config gives:

HandshakeFailed (Error_Protocol ("certificate rejected: [NameMismatch \"<redacted>\"]",True,CertificateUnknown))

Compilation error `Invalid type signature: F :: ...`

Hey @barrucadu ,

on my machine (running macOS 10.13.3) stack fails to build irc-client-1.1.0.1:

$ git clone https://github.com/barrucadu/irc-client
Cloning into 'irc-client'...
remote: Counting objects: 994, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 994 (delta 0), reused 2 (delta 0), pack-reused 990
Receiving objects: 100% (994/994), 193.06 KiB | 156.00 KiB/s, done.
Resolving deltas: 100% (460/460), done.
$ cd irc-client/
$ stack build
irc-conduit-0.3.0.0: configure
irc-conduit-0.3.0.0: build
irc-conduit-0.3.0.0: copy/register
irc-client-1.1.0.1: configure (lib)
Configuring irc-client-1.1.0.1...
irc-client-1.1.0.1: build (lib)
Preprocessing library irc-client-1.1.0.1...
[1 of 8] Compiling Paths_irc_client ( .stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/autogen/Paths_irc_client.hs, .stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/Paths_irc_client.o )
[2 of 8] Compiling Network.IRC.Client.Internal.Types ( Network/IRC/Client/Internal/Types.hs, .stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/Network/IRC/Client/Internal/Types.o )
[3 of 8] Compiling Network.IRC.Client.Internal.Lens ( Network/IRC/Client/Internal/Lens.hs, .stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/Network/IRC/Client/Internal/Lens.o )
[4 of 8] Compiling Network.IRC.Client.Lens ( Network/IRC/Client/Lens.hs, .stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/Network/IRC/Client/Lens.o )
             
/Users/jan/Documents/dev/haskell/irc-client/Network/IRC/Client/Lens.hs:52:81: error:
    Invalid type signature: F :: ...
    Should be of form <variable> :: <type>
             
--  While building custom Setup.hs for package irc-client-1.1.0.1 using:
      /Users/jan/.stack/setup-exe-cache/x86_64-osx/Cabal-simple_mPHDZzAJ_1.24.2.0_ghc-8.0.2 --builddir=.stack-work/dist/x86_64-osx/Cabal-1.24.2.0 build lib:irc-client --ghc-options " -ddump-hi -ddump-to-file"
    Process exited with code: ExitFailure 1
Completed 2 action(s).
$ stack exec -- ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.0.2

Have you seen this before and know of a solution or workaround?

Edit
Latest version I can compile successfully is 0.4.4.4, 1.0.0.0 is the first one that is failing.

How do I trigger stuff after runner's initialise sends USER/NICK?

It looks like there's no event to be triggered. Maybe instanceConfig >>= mapM_ (send . Join) . _channels ought to be put in its own initHandler that you can then override and delegate to after/before your own code's been run? You could pass empty strings for _raw, _message and _source.

There's also the option, albeit not a very attractive one, of dragging a initCallback argument from start to runner.

GHC 8 compatibility

Can't support GHC 8 yet because of not-yet-updated dependencies:

While constructing the BuildPlan the following exceptions were encountered:

--  Failure when adding dependencies:    
      mono-traversable: needed (>=0.2), couldn't resolve its dependencies
    needed for package: chunked-data-0.2.0

--  Failure when adding dependencies:    
      chunked-data: needed (-any), couldn't resolve its dependencies
      mono-traversable: needed (>=0.5), couldn't resolve its dependencies
    needed for package: conduit-combinators-1.0.3.1

--  Failure when adding dependencies:    
      stm-conduit: needed (>=2.5), couldn't resolve its dependencies
    needed for package: irc-client-0.3.0.0

--  Failure when adding dependencies:    
      vector-instances: needed (-any), couldn't resolve its dependencies
    needed for package: mono-traversable-0.10.2

--  Failure when adding dependencies:    
      data-default-class: needed (>=0.0.1 && <0.1), 0.1.0 found (latest applicable is 0.0.1)
    needed for package: pointed-5

--  Failure when adding dependencies:    
      conduit-combinators: needed (>=0.3), couldn't resolve its dependencies
      transformers: needed (>=0.2 && <0.5), 0.5.2.0 found (latest applicable is 0.4.3.0)
    needed for package: stm-conduit-2.8.0

--  Failure when adding dependencies:    
      pointed: needed (>=3), couldn't resolve its dependencies
    needed for package: vector-instances-3.3.1

Wait for a bit, and then rewrite things if dependencies don't get updated soon.

Please make a new hackage release

I just tried building this package from hackage, and compilation failed with some type mismatch regarding TimeLocale. I suspect that da56412 fixes that, but that is not on hackage.

Thank you very much.

Client-side timeout

Sometimes yukibot will drop off freenode, but the process will remain running. This means that network-conduit (or something) hasn't noticed the disconnect. A client-side timeout to initiate a disconnect if the server doesn't respond to a message in long enough would solve this.

Significantly higher CPU usage when using threaded runtime

00:30 < ij> https://i.imgur.com/qyB5ML7.png
00:31 < ij> with lts-7.0, irc-client-1.0.0.0 at 249115ef, irc-conduit at 7da6817, tag: 0.2.2.0
00:37 < ij> https://gist.github.com/siers/823a7f84913e1d6a2d567b9c1ba00424
00:41 < barrucadu> Ah, now I get it. Alright, I just changed like 4 things, let's try to narrow it down
00:44 < barrucadu> It's -threaded. The threaded runtime uses significantly more CPU for some reason, hmm.
00:45 < barrucadu> I'll do some profiling and try to figure out where the difference is
00:45 < ij> \o/ No way, I found a bug.
00:46 < barrucadu> I'm kinda concerned that just passing -threaded is enough to trigger this, even without +RTS -N, as that means the threaded runtime with a single core is doing significantly worse
                   than the non-threaded runtime with a single core for some reason...
00:47 < barrucadu> And I feel like that shouldn't really happen

Unfortunately, execution time profiling doesn't really show a difference between the two.

Event handler threads should get killed on disconnect.

When the client disconnects, any event handler threads are left to run. They should be killed. Probably the easiest way to do this:

  1. Have an MVar [ThreadId] in IrcState.
  2. Have the forked thread in eventSink write its ThreadId to that list on start.
  3. Have the forked thread in eventSink remove its ThreadId from that list on stop (with appropriate handling of an exception killing that thread).
  4. Kill all remaining threads in disconnect (a new Disconnected exception, perhaps?)

Request: State in IRC

Would it be possible to make a transformer IRCT to add a state? I'd like to set some kind of variable in one event and evaluate it in another.

Make logging optional

Hi

https://github.com/barrucadu/irc-client/blob/4fdd90342c410f72e1197ffb4452c44fdcb2118b/Network/IRC/Client/Internal.hs#L77-78

logConduit writes everything to stdout without an option of turning that off. Since irc-client is a library, it should not do that (it would interfere with the application's normal stdout usage).

Please either remove the logger altogether, or make it optional by passing a function through connect' and ConnectionConfig that is called in place of putStrLn.

Drop EventHandler _description

It's not used for anything. Initially I planned to generate help text based on the event handlers, but in practice I've found I typically have one big event handler which runs all the commands and suchlike, themselves managed at a higher level of abstraction.

Unable to disconnect gracefully

Is there a way to gracefully disconnect?

One quick fix to make disconnect work would be to replace awaitForever with await and just not loop as soon as the send queue is closed. This then terminates the message decoding pipeline after receiving one further message.

-- | Block on receiving a message and invoke all matching handlers
-- concurrently.
eventSink :: MonadIO m => IRCState s -> Consumer IrcEvent m ()
eventSink ircstate = await >>= maybe (return ()) (\event -> do
  let event'  = decodeUtf8 <$> event
  ignored <- isIgnored ircstate event'
  unless ignored $ do
    handlers <- getHandlersFor event' . _eventHandlers <$> getInstanceConfig' ircstate
    liftIO $ mapM_ (\h -> forkIO $ runReaderT (h event') ircstate) handlers

  -- If no more events are expected, we can terminate this sink.
  disconnected <- isDisconnected ircstate
  unless disconnected $
    eventSink ircstate)

-- | Check if the connection is already meant to be closed.
isDisconnected :: MonadIO m => IRCState s -> m Bool
isDisconnected ircstate = do
  let queueS  = _sendqueue $ getConnectionConfig ircstate
  liftIO . atomically $ isClosedTBMChan queueS

If you are fine with this approach, I can submit a PR. It probably would be cleaner to explicitly encode the state of the connection in IRCState though.

What do you think?

Unexport record accessors, export lenses.

Exporting the record accessors directly means I can't add new record fields without breaking backwards compatibility. If only lenses are exported, and a function to construct a "default" record, additive changes are compatible.

This will also be more useful than the currently-exposed accessor functions, which don't work for modification

Not ignoring messages from the server that failed to decode?

I'm using this library for interacting with a server that has a few custom features built on top of standard IRC. But since these don't decode into a standard IRC message, they are just dropped and there's no way to handle them. I think it would be useful to have these decode into a RawMsg instead, since at the moment (it seems like) there's no other way of getting access to these.

1.0 release (feedback desired)

I'm planning on fixing #12, #20, #21, #22, #23, and releasing version 0.51.0.

In the process of working on #23, I found myself wondering just what things need to be exposed. Specifically, do any lenses for ConnectionConfig need to be exposed at all? In yukibot I never modify the ConnectionConfig after creation, and creation lets you set all the fields it makes sense to set. To check I haven't missed anything, I'd appreciate it if anyone who does modify ConnectionConfig after calling one of the connect* functions could let me know: @siers, @JanGe.

Also, any other feature requests for 0.51.0, let me know.

Does IRC mix with IO?

Is it possible to do execute IRC actions inside an IO, for example, while locking with withMVar :: MVar a -> (a -> IO b) -> IO b?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.