This commit is contained in:
Liam Stanley 2017-01-16 02:23:09 -05:00
commit 6e09205dd9
3 changed files with 67 additions and 15 deletions

@ -1,19 +1,30 @@
## girc is a flexible IRC library for Go
[![Build Status](https://travis-ci.org/lrstanley/girc.svg?branch=master)](https://travis-ci.org/lrstanley/girc)
[![GoDoc](https://godoc.org/github.com/lrstanley/girc?status.png)](https://godoc.org/github.com/lrstanley/girc)
[![Go Report Card](https://goreportcard.com/badge/github.com/lrstanley/girc)](https://goreportcard.com/report/github.com/lrstanley/girc)
[![IRC Chat](https://img.shields.io/badge/ByteIRC-%23L-blue.svg)](http://byteirc.org/channel/L)
[![GitHub Issues](https://img.shields.io/github/issues/lrstanley/girc.svg)](https://github.com/lrstanley/girc/issues)
[![license](https://img.shields.io/github/license/lrstanley/girc.svg)](https://raw.githubusercontent.com/lrstanley/girc/master/LICENSE)
<p align="center"><a href="https://godoc.org/github.com/lrstanley/girc"><img width="600" src="https://i.imgur.com/Wh6otgh.png"></a></p>
<p align="center">girc -- A flexible IRC library for Go</p>
<p align="center">
<a href="https://travis-ci.org/lrstanley/girc"><img src="https://travis-ci.org/lrstanley/girc.svg?branch=master" alt="Build Status"></a>
<a href="https://godoc.org/github.com/lrstanley/girc"><img src="https://godoc.org/github.com/lrstanley/girc?status.png" alt="GoDoc"></a>
<a href="https://goreportcard.com/report/github.com/lrstanley/girc"><img src="https://goreportcard.com/badge/github.com/lrstanley/girc" alt="Go Report Card"></a>
<a href="http://byteirc.org/channel/L"><img src="https://img.shields.io/badge/ByteIRC-%23L-blue.svg" alt="IRC Chat"></a>
<a href="https://github.com/lrstanley/girc/issues"><img src="https://img.shields.io/github/issues/lrstanley/girc.svg" alt="GitHub Issues"></a>
<a href="https://raw.githubusercontent.com/lrstanley/girc/master/LICENSE"><img src="https://img.shields.io/github/license/lrstanley/girc.svg" alt="License"></a>
</p>
## Features
- Focuses on simplicity, yet tries to still be flexible
- Only requires standard packages
- Event based triggering/responses
- Documentation is mostly on par
- At this time, **expect breaking changes to occur frequently**.
- Focuses on simplicity, yet tries to still be flexible.
- Only requires standard library packages.
- Event based triggering/responses (and CTCP too!).
- Documentation is mostly on par.
- Full support for the IRCv3 spec. [**WIP**]
- Channel and user tracking. Easily find what users are in a channel, if a user is away, or if they are authenticated.
- Client state/capability tracking. Easy methods to access capability data.
- Built-in support for things you would commmonly have to implement yourself.
- Nick collision detection and prevention.
- Event/message rate limiting.
- Channel, nick, and user validation on connection methods.
- CTCP handling and auto-responses.
- At this time, **expect breaking changes to occur frequently**. girc has **not hit version 1.0.0 yet!**
## TODO
@ -30,10 +41,13 @@
- [ ] write more function-specific examples as the api becomes much more stable
- [ ] client should support ping tracking (sending `PING`'s to the server)
- [ ] with this, we can potentially find lag. `Client.Lag()` would be useful
- [ ] users need to be exposed in state somehow (other than `GetChannels()`)
- [ ] allow support for changing the frequency of this?
- [ ] users need to be exposed in state some how (other than `GetChannels()`)
- [ ] `MODE` tracking on a per-channel basis
- [ ] `Client.AddTmpCallback()` for one time use callbacks?
- [ ] add option to enable PRIVMSG/NOTICE text wrapping (and maybe per-default?) (`Config.DisableResponseWrap`?)
- [ ] allow support for proxy URLs (passing to `golang.org/x/net/proxy`?)
- [ ] allow users to specify a local/bind address using `net.Dialer{}.LocalAddr`
- [ ] add more generic helpers: `Away()`, `Invite()`, `Kick()`, `Oper()`, generic `Ping()` and `Pong()`, `VHost()`, `Whois()` and `Who()`
## Installing

@ -36,6 +36,8 @@ type Client struct {
// tries represents the internal reconnect count to the IRC server.
tries int
// limiter is a configurable EventLimiter by the end user.
limiter *EventLimiter
// log is used if a writer is supplied for Client.Config.Logger.
log *log.Logger
// quitChan is used to stop the read loop. See Client.Quit().
@ -67,6 +69,9 @@ type Config struct {
// MaxRetries is the number of times the client will attempt to reconnect
// to the server after the last disconnect.
MaxRetries int
// RateLimit is the delay in seconds between events sent to the server,
// with a burst of 4 messages. Set to -1 to disable.
RateLimit int
// Logger is an optional, user supplied logger to log the raw lines sent
// from the server. Useful for debugging. Defaults to ioutil.Discard.
Logger io.Writer
@ -74,6 +79,10 @@ type Config struct {
// support. Only use this if DisableTracking and DisableCapTracking are
// not enabled, otherwise you will need to handle CAP negotiation yourself.
SupportedCaps []string
// Version is the application version information that will be used in
// response to a CTCP VERSION, if default CTCP replies have not been
// overwritten or a VERSION handler was already supplied.
Version string
// ReconnectDelay is the a duration of time to delay before attempting a
// reconnection. Defaults to 10s (minimum of 10s).
ReconnectDelay time.Duration
@ -127,6 +136,13 @@ func New(config Config) *Client {
}
client.log = log.New(client.Config.Logger, "", log.Ldate|log.Ltime|log.Lshortfile)
// Setup a rate limiter if they requested one.
if client.Config.RateLimit == 0 {
client.limiter = NewEventLimiter(4, 1*time.Second, client.write)
} else if client.Config.RateLimit > 0 {
client.limiter = NewEventLimiter(4, time.Duration(client.Config.RateLimit)*time.Second, client.write)
}
// Give ourselves a new state.
client.state = newState()
@ -160,6 +176,12 @@ func (c *Client) Quit(message string) {
// Stop exits the clients main loop. Use Client.Quit() first if you want to
// disconnect the client from the server/connection.
func (c *Client) Stop() {
// Close and limiters they have, otherwise the client could be easily
// held in memory.
if c.limiter != nil {
c.limiter.Stop()
}
// Send to the stop channel, so if Client.Loop() is being used, this will
// return.
c.stopChan <- struct{}{}
@ -354,6 +376,17 @@ func (c *Client) Lifetime() time.Duration {
// Send sends an event to the server. Use Client.RunCallback() if you are
// simply looking to trigger callbacks with an event.
func (c *Client) Send(event *Event) error {
// if the client wants us to rate limit incoming events, do so, otherwise
// simply use the underlying send functionality.
if c.limiter != nil {
return c.limiter.Send(event)
}
return c.write(event)
}
// write is the lower level function to write an event.
func (c *Client) write(event *Event) error {
// log the event
if !event.Sensitive {
c.log.Print("--> ", StripRaw(event.Raw()))

@ -251,6 +251,11 @@ func handleCTCPPong(client *Client, ctcp CTCPEvent) {
// as the os type (darwin, linux, windows, etc) and architecture type (x86,
// arm, etc).
func handleCTCPVersion(client *Client, ctcp CTCPEvent) {
if client.Config.Version != "" {
client.SendCTCPReply(ctcp.Source.Name, CTCP_VERSION, client.Config.Version)
return
}
client.SendCTCPReplyf(
ctcp.Source.Name, CTCP_VERSION,
"girc (github.com/lrstanley/girc) using %s (%s, %s)",