Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 75: IMPLEMENT NAMES sendraw and 353 and 366 callbacks #76

Closed
wants to merge 3 commits into from
Closed

Issue 75: IMPLEMENT NAMES sendraw and 353 and 366 callbacks #76

wants to merge 3 commits into from

Conversation

jrmiller82
Copy link

Here you go.

1 new func, 2 new callbacks, and 2 global vars.

There's likely a cleaner way to do the concurrency and the global vars, but you don't know how many 353 events you will have before a 366. Also, there may be use cases where someone is calling a ton of different irc channels and receiving 353 events from multiple channels (i.e. at initial connection to all channels).
It's a little dirty, but it's working fantastically for my single-irc-channel bot at the moment. Might need some concurrency cleaning up with mutexes / better channels than my implementation in the future.

@belak
Copy link
Contributor

belak commented Jul 20, 2016

A few things:

  • Callbacks aren't in goroutines by default. We shouldn't need to communicate between them... There's got to be a better way. Maybe by storing a map[string][]string rather than a map[string]chan string
  • When you JOIN a channel, you should get RPL_NAMREPLY and RPL_ENDOFNAMES automatically, so I'm not sure if you need the additional GetNicksOnChan function.
  • The name maps should probably be attached to the client, rather than global.
  • I personally prefer https://tools.ietf.org/html/rfc1459#section-4.2.5 because rfc2812 has a number of inconsistencies with the protocol and isn't widely implemented (even though parts of it are).

@jrmiller82
Copy link
Author

The GetNicksOnChan function is so the client can trigger RPL_NAMEREPLY etc...

Issue 75: thoj invited a PR, I attempted. Do you have a better way of containing this functionality in the library and not the client? I won't be offended if you rip it to shreds or change it. (I'll likely just keep using my fork for the time being).

I also used rfc2xxx because that's what was linked to me in issue 75.

Feel free to change it and improve it.

@belak
Copy link
Contributor

belak commented Jul 20, 2016

Sorry if I came across as harsh. It's awesome you were willing to do this. Also keep in mind that I'm not the owner of this repo, just someone with a vested interest in golang irc libraries. I haven't gotten around to implementing this in my go IRC library either because of how complicated it can be.

I was imagining something similar to https://github.com/belak/python-seabird/blob/master/seabird/modules/track.py (store which nicks are in which channels) but without all the mode tracking, as it removes a bunch of race conditions, but that's a completely different direction.

Both methods have downsides.

Downsides of your method:

  • Can't be used by multiple callbacks - nicks will be lost
  • Will (currently) leak goroutines if the channels are not serviced.

Downsides of the more complicated method:

  • It's much more complicated and error prone.
  • Has the potential to do work that isn't needed.

@jrmiller82
Copy link
Author

If I change the 366 callback to blocking instead of a go-routine, it shouldn't leak, right?

How does it lose nicks? No other callback other than 353 should be triggering it, so... what am I missing? :)

@belak
Copy link
Contributor

belak commented Jul 21, 2016

Ok, I guess I misunderstood the code before and this should actually work. Really sorry about the confusion. :(

The channel could be avoided completely by changing the maps to something like this:

var tempNickMap = map[string][]string{}
var NickChanState = map[string][]string{}

Then, any time 353 is called, it would add the nicks to the tempNickMap and when 366 is called, the nicks could be moved from nickStaging to NickChanState.

It would be best to attach those to the *Connection struct though, as they're scoped to the connection.

You could avoid compiling the regex on each call of the hander by moving that to a global variable, as that's scoped to the package, not the handler.

@thoj
Copy link
Owner

thoj commented Jul 21, 2016

Thanks for the PR! :) This has given me some ideas 👍

I feel global variables are unnecessary. Why no store channel data in the Connection struct? If you do that you can create a Channel and User struct. Something like this:

type Connection struct {
    sync.WaitGroup
    Debug     bool
...Snip
        Channels  map[string]Channel
...Snip
}

type Channel struct {
     Name string
     Users map[string]User
     etc...
}

type User struct {
   Nick string
   Host string
   Name string //Real Name?
   etc..?
}

So when you get a 353 callback you just do something with with irc.Channels. Add channel and add Users etc. You also need to track users leaving and joining the channel to keep the list up to date.

@jrmiller82
Copy link
Author

That is likely smart to do it in the Connection struct. Just haven't had time to do any more work on it.

@thoj
Copy link
Owner

thoj commented Jul 21, 2016

You where way to fast 👍 . I updated my comment. hehe.

@jrmiller82
Copy link
Author

That does look good. :)

@jrmiller82
Copy link
Author

My fault for not groking the Connection struct enough.

@thoj
Copy link
Owner

thoj commented Jul 21, 2016

Hacked together this:
ad4ec27

This patch breaks tests but it tracks users from the 353 callback. It dosent track joins and parts and we probably need to split out modes and stuff. Maybe you can build a bit on this? I need to go to bed. Hehe.

@kevinpostal
Copy link

+1 Love watching the progress guys.

Let me know if any way I can contribute!

@thoj
Copy link
Owner

thoj commented Jul 27, 2016

@kevinpostal @jrmiller82 @belak

New commit needs testing and comments: 9f2cfa5 on nick tracker branch. Seems to work fine for most stuff at my end. Se tests how to use.

irccon.SetupNickTrack() will add the necessary callbacks that will populate irc.Channels.

@thoj
Copy link
Owner

thoj commented Jul 27, 2016

Example:

package main

import (
        "fmt"
        "github.com/thoja/go-ircevent"
        "sort"
        "time"
)

const channel = "#whaterver"
const serverssl = "irc.whatevernet.net:6667"

func main() {
        ircnick1 := "blatibalt1"
        irccon := irc.IRC(ircnick1, "blatiblat")
        irccon.VerboseCallbackHandler = true
        irccon.Debug = true
        irccon.AddCallback("001", func(e *irc.Event) { irccon.Join(channel) })
        irccon.AddCallback("366", func(e *irc.Event) {})
        irccon.SetupNickTrack()
        err := irccon.Connect(serverssl)
        if err != nil {
                fmt.Printf("Err %s", err)
                return
        }
        go func() {
                t := time.NewTicker(1 * time.Second)
                for {
                        <-t.C
                        var keys []string
                        if _, ok := irccon.Channels[channel]; ok == true {
                                for k, _ := range irccon.Channels[channel].Users {
                                        keys = append(keys, k)
                                }
                                sort.Strings(keys)
                                fmt.Printf("%d: ", len(keys))
                                for _, k := range keys {
                                        fmt.Printf("(%s)%s ", irccon.Channels[channel].Users[k].Mode, k)
                                }
                                fmt.Printf("\n")
                        }
                }
        }()
        irccon.Loop()
}

@thoj
Copy link
Owner

thoj commented Jul 28, 2016

See #79

@thoj thoj closed this Jul 28, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants