implement GetServerOption, ServerName, NetworkName, ServerVersion, and ISUPPORT tracking; update todos
This commit is contained in:
parent
0870acadcb
commit
687e2753a1
@ -28,7 +28,6 @@
|
|||||||
- [ ] ensure types `User` and `Channel` don't have any unexported fields, and that when they are given publically, it's not a pointer to internal state
|
- [ ] ensure types `User` and `Channel` don't have any unexported fields, and that when they are given publically, it's not a pointer to internal state
|
||||||
- [ ] track with `NAMES` as well? would require rewrite of user existance logic, could also help track user modes
|
- [ ] track with `NAMES` as well? would require rewrite of user existance logic, could also help track user modes
|
||||||
- [ ] write more function-specific examples as the api becomes much more stable
|
- [ ] write more function-specific examples as the api becomes much more stable
|
||||||
- [ ] would be cool to track things like `SERVERNAME`, `VERSION`, `UMODES`, `CMODES`, etc. also see `Config.DisableCapTracking`. [e.g. here](https://github.com/lrstanley/Code/blob/master/core/triggers.py#L40-L67)
|
|
||||||
- [ ] client should support ping tracking (sending `PING`'s to the server)
|
- [ ] client should support ping tracking (sending `PING`'s to the server)
|
||||||
- [ ] with this, we can potentially find lag. `Client.Lag()` would be useful
|
- [ ] with this, we can potentially find lag. `Client.Lag()` would be useful
|
||||||
- [ ] users need to be exposed in state somehow (other than `GetChannels()`)
|
- [ ] users need to be exposed in state somehow (other than `GetChannels()`)
|
||||||
|
42
client.go
42
client.go
@ -707,3 +707,45 @@ func (c *Client) Whowas(nick string, amount int) error {
|
|||||||
|
|
||||||
return c.Send(&Event{Command: WHOWAS, Params: []string{nick, string(amount)}})
|
return c.Send(&Event{Command: WHOWAS, Params: []string{nick, string(amount)}})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetServerOption retrieves a server capability setting that was retrieved
|
||||||
|
// during client connection. This is also known as ISUPPORT. Examples of usage:
|
||||||
|
//
|
||||||
|
// nickLen, success := GetServerOption("MAXNICKLEN")
|
||||||
|
//
|
||||||
|
func (c *Client) GetServerOption(key string) (result string, success bool) {
|
||||||
|
if c.Config.DisableTracking {
|
||||||
|
panic("GetServerOption() used when tracking is disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.state.mu.Lock()
|
||||||
|
result, success = c.state.serverOptions[key]
|
||||||
|
c.state.mu.Unlock()
|
||||||
|
|
||||||
|
return result, success
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerName returns the server host/name that the server itself identifies
|
||||||
|
// as. May be empty if the server does not support RPL_MYINFO.
|
||||||
|
func (c *Client) ServerName() (name string) {
|
||||||
|
name, _ = c.GetServerOption("SERVER")
|
||||||
|
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkName returns the network identifier. E.g. "EsperNet", "ByteIRC".
|
||||||
|
// May be empty if the server does not support RPL_ISUPPORT.
|
||||||
|
func (c *Client) NetworkName() (name string) {
|
||||||
|
name, _ = c.GetServerOption("NETWORK")
|
||||||
|
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerVersion returns the server software version, if the server has
|
||||||
|
// supplied this information during connection. May be empty if the server
|
||||||
|
// does not support RPL_MYINFO.
|
||||||
|
func (c *Client) ServerVersion() (version string) {
|
||||||
|
version, _ = c.GetServerOption("VERSION")
|
||||||
|
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
52
handlers.go
52
handlers.go
@ -4,7 +4,10 @@
|
|||||||
|
|
||||||
package girc
|
package girc
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// registerHandlers sets up built-in callbacks/helpers, based on client
|
// registerHandlers sets up built-in callbacks/helpers, based on client
|
||||||
// configuration.
|
// configuration.
|
||||||
@ -32,6 +35,8 @@ func (c *Client) registerHandlers() {
|
|||||||
// Other misc. useful stuff.
|
// Other misc. useful stuff.
|
||||||
c.Callbacks.register(true, TOPIC, CallbackFunc(handleTOPIC))
|
c.Callbacks.register(true, TOPIC, CallbackFunc(handleTOPIC))
|
||||||
c.Callbacks.register(true, RPL_TOPIC, CallbackFunc(handleTOPIC))
|
c.Callbacks.register(true, RPL_TOPIC, CallbackFunc(handleTOPIC))
|
||||||
|
c.Callbacks.register(true, RPL_MYINFO, CallbackFunc(handleMYINFO))
|
||||||
|
c.Callbacks.register(true, RPL_ISUPPORT, CallbackFunc(handleISUPPORT))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nickname collisions.
|
// Nickname collisions.
|
||||||
@ -64,7 +69,7 @@ func handleConnect(c *Client, e Event) {
|
|||||||
c.state.nick = e.Params[0]
|
c.state.nick = e.Params[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
c.Events <- &Event{Command: CONNECTED}
|
c.Events <- &Event{Command: CONNECTED}
|
||||||
}
|
}
|
||||||
@ -226,3 +231,46 @@ func handleQUIT(c *Client, e Event) {
|
|||||||
c.state.deleteUser(e.Source.Name)
|
c.state.deleteUser(e.Source.Name)
|
||||||
c.state.mu.Unlock()
|
c.state.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleMYINFO(c *Client, e Event) {
|
||||||
|
// Malformed or odd output. As this can differ strongly between networks,
|
||||||
|
// just skip it.
|
||||||
|
if len(e.Params) < 3 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.state.mu.Lock()
|
||||||
|
c.state.serverOptions["SERVER"] = e.Params[1]
|
||||||
|
c.state.serverOptions["VERSION"] = e.Params[2]
|
||||||
|
c.state.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleISUPPORT(c *Client, e Event) {
|
||||||
|
// Must be a ISUPPORT-based message. 005 is also used for server bounce
|
||||||
|
// related things, so this callback may be triggered during other
|
||||||
|
// situations.
|
||||||
|
if !strings.HasSuffix(e.Trailing, "this server") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must have at least one configuration.
|
||||||
|
if len(e.Params) < 2 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.state.mu.Lock()
|
||||||
|
// Skip the first parameter, as it's our nickname.
|
||||||
|
for i := 1; i < len(e.Params); i++ {
|
||||||
|
j := strings.IndexByte(e.Params[i], 0x3D) // =
|
||||||
|
|
||||||
|
if j < 1 || (j+1) == len(e.Params[i]) {
|
||||||
|
c.state.serverOptions[e.Params[i]] = ""
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
name := e.Params[i][0:j]
|
||||||
|
val := e.Params[i][j+1:]
|
||||||
|
c.state.serverOptions[name] = val
|
||||||
|
}
|
||||||
|
c.state.mu.Unlock()
|
||||||
|
}
|
||||||
|
5
state.go
5
state.go
@ -44,6 +44,10 @@ type state struct {
|
|||||||
// last capability check. These will get sent once we have received the
|
// last capability check. These will get sent once we have received the
|
||||||
// last capability list command from the server.
|
// last capability list command from the server.
|
||||||
tmpCap []string
|
tmpCap []string
|
||||||
|
// serverOptions are the standard capabilities and configurations
|
||||||
|
// supported by the server at connection time. This also includes ISUPPORT
|
||||||
|
// entries.
|
||||||
|
serverOptions map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// User represents an IRC user and the state attached to them.
|
// User represents an IRC user and the state attached to them.
|
||||||
@ -168,6 +172,7 @@ func newState() *state {
|
|||||||
s := &state{}
|
s := &state{}
|
||||||
|
|
||||||
s.channels = make(map[string]*Channel)
|
s.channels = make(map[string]*Channel)
|
||||||
|
s.serverOptions = make(map[string]string)
|
||||||
s.connected = false
|
s.connected = false
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
Loading…
Reference in New Issue
Block a user