Browse Source

add ctcp handlers, and improve destroyed handling.

master
Gisle Aune 4 years ago
parent
commit
9284fe2c7c
  1. 27
      client.go
  2. 62
      handlers/ctcp.go
  3. 2
      handlers/mroleplay.go

27
client.go

@ -60,6 +60,9 @@ var ErrTargetNotFound = errors.New("irc: target not found")
// status target
var ErrTargetIsStatus = errors.New("irc: cannot remove status target")
// ErrDestroyed is returned by Client.Connect if you try to connect a destroyed client.
var ErrDestroyed = errors.New("irc: client destroyed")
// A Client is an IRC client. You need to use New to construct it
type Client struct {
id string
@ -114,6 +117,8 @@ func New(ctx context.Context, config Config) *Client {
go client.handleEventLoop()
go client.handleSendLoop()
client.EmitNonBlocking(NewEvent("client", "create"))
return client
}
@ -249,15 +254,26 @@ func (client *Client) Connect(addr string, ssl bool) (err error) {
InsecureSkipVerify: client.config.SkipSSLVerification,
})
if err != nil {
if !client.Destroyed() {
client.EmitNonBlocking(NewErrorEvent("connect", "Connect failed: "+err.Error()))
}
return err
}
} else {
conn, err = net.Dial("tcp", addr)
if err != nil {
if !client.Destroyed() {
client.EmitNonBlocking(NewErrorEvent("connect", "Connect failed: "+err.Error()))
}
return err
}
}
if client.Destroyed() {
_ = conn.Close()
return ErrDestroyed
}
client.EmitNonBlocking(NewEvent("client", "connect"))
go func() {
@ -435,6 +451,11 @@ func (client *Client) Describef(targetName string, format string, a ...interface
// wait for the event, or the client's destruction.
func (client *Client) Emit(event Event) context.Context {
event.ctx, event.cancel = context.WithCancel(client.ctx)
if client.Destroyed() {
event.cancel()
return event.ctx
}
client.events <- &event
return event.ctx
@ -445,6 +466,10 @@ func (client *Client) Emit(event Event) context.Context {
// returned context is for.
func (client *Client) EmitNonBlocking(event Event) context.Context {
event.ctx, event.cancel = context.WithCancel(client.ctx)
if client.Destroyed() {
event.cancel()
return event.ctx
}
select {
case client.events <- &event:
@ -1374,7 +1399,7 @@ func (client *Client) handleEvent(event *Event) {
client.handleInTarget(channel, event)
}
} else {
// Try to target by mentioned channel name
// Try to target by mentioned channel name.
for _, token := range strings.Fields(event.Text) {
if client.isupport.IsChannel(token) {
channel := client.Channel(token)

62
handlers/ctcp.go

@ -0,0 +1,62 @@
package handlers
import (
"github.com/gissleh/irc"
"strconv"
"strings"
"time"
)
// CTCP implements the widely used CTCP commands (CLIENTINFO, VERSION, TIME, and PING), as well as the /ping command.
// It does not implement DCC.
//
// For every other CTCP command supported, you should expand the `ctcp.clientinfo.reply` client value like above.
func CTCP(event *irc.Event, client *irc.Client) {
switch event.Name() {
case "client.create":
if r, ok := client.Value("ctcp.clientinfo.reply").(string); ok {
if !strings.Contains(r, "ACTION PING TIME VERSION") {
client.SetValue("ctcp.clientinfo.reply", r+" ACTION PING TIME VERSION")
}
} else {
client.SetValue("ctcp.clientinfo.reply", "ACTION PING TIME VERSION")
}
case "ctcp.clientinfo":
{
response, ok := client.Value("ctcp.clientinfo.reply").(string)
if !ok {
response = "ACTION PING TIME VERSION"
}
client.SendCTCP("CLIENTINFO", event.Nick, true, response)
}
case "ctcp.version":
{
version := "github.com/gissleh/irc v1.0"
if v, ok := client.Value("ctcp.version.reply").(string); ok {
version = v
}
client.SendCTCP("VERSION", event.Nick, true, version)
}
case "ctcp.time":
{
client.SendCTCP("TIME", event.Nick, true, time.Now().Local().Format(time.RFC1123))
}
case "ctcp.ping":
{
client.SendCTCP("PING", event.Nick, true, event.Text)
}
case "input.ping":
{
args := strings.SplitN(event.Text, " ", 2)
targetName := args[0]
if targetName == "" {
client.EmitNonBlocking(irc.NewErrorEvent("ctcp.pingarg", "/ping needs an argument"))
break
}
client.SendCTCP("PING", targetName, false, strconv.FormatInt(time.Now().UnixNano()/1000000, 10))
}
}
}

2
handlers/mroleplay.go

@ -99,7 +99,7 @@ func MRoleplay(event *irc.Event, client *irc.Client) {
case "input.scenec", "input.narratorc":
{
if event.Text == "" {
client.EmitNonBlocking(irc.NewErrorEvent("input", "Usage: /scenec <text...>"))
client.EmitNonBlocking(irc.NewErrorEvent("input", "Usage: /"+event.Verb()+" <text...>"))
break
}

Loading…
Cancel
Save