Browse Source

rework target ID handling to be less clunky.

master
Gisle Aune 3 years ago
parent
commit
714b80d6e7
  1. 6
      channel.go
  2. 75
      client.go
  3. 2
      cmd/ircrepl/main.go
  4. 13
      event.go
  5. 6
      query.go
  6. 6
      status.go
  7. 1
      target.go

6
channel.go

@ -8,11 +8,17 @@ import (
// A Channel is a target that manages the userlist
type Channel struct {
id string
name string
userlist *list.List
parted bool
}
// ID returns a unique ID for the channel target.
func (channel *Channel) ID() string {
return channel.id
}
// Kind returns "channel"
func (channel *Channel) Kind() string {
return "channel"

75
client.go

@ -87,9 +87,8 @@ type Client struct {
isupport isupport.ISupport
values map[string]interface{}
status *Status
targets []Target
targetIds map[Target]string
status *Status
targets []Target
handlers []Handler
}
@ -105,13 +104,12 @@ func New(ctx context.Context, config Config) *Client {
capEnabled: make(map[string]bool),
capData: make(map[string]string),
config: config.WithDefaults(),
targetIds: make(map[Target]string, 16),
status: &Status{},
status: &Status{id: generateClientID("T")},
}
client.ctx, client.cancel = context.WithCancel(ctx)
_, _ = client.AddTarget(client.status)
_ = client.AddTarget(client.status)
go client.handleEventLoop()
go client.handleSendLoop()
@ -220,7 +218,7 @@ func (client *Client) State() ClientState {
for _, target := range client.targets {
tstate := target.State()
tstate.ID = client.targetIds[target]
tstate.ID = target.ID()
state.Targets = append(state.Targets, tstate)
}
@ -484,7 +482,7 @@ func (client *Client) EmitInput(line string, target Target) context.Context {
event := ParseInput(line)
client.mutex.RLock()
if target != nil && client.targetIds[target] == "" {
if target != nil && client.TargetByID(target.ID()) == nil {
client.EmitNonBlocking(NewErrorEvent("invalid_target", "Target does not exist."))
ctx, cancel := context.WithCancel(context.Background())
@ -496,12 +494,10 @@ func (client *Client) EmitInput(line string, target Target) context.Context {
if target != nil {
client.mutex.RLock()
event.targets = append(event.targets, target)
event.targetIds[target] = client.targetIds[target]
client.mutex.RUnlock()
} else {
client.mutex.RLock()
event.targets = append(event.targets, client.status)
event.targetIds[client.status] = client.targetIds[client.status]
client.mutex.RUnlock()
}
@ -594,6 +590,20 @@ func (client *Client) Target(kind string, name string) Target {
return nil
}
// TargetByID gets a target by kind and name
func (client *Client) TargetByID(id string) Target {
client.mutex.RLock()
defer client.mutex.RUnlock()
for _, target := range client.targets {
if target.ID() == id {
return target
}
}
return nil
}
// Targets gets all targets of the given kinds.
func (client *Client) Targets(kinds ...string) []Target {
if len(kinds) == 0 {
@ -658,7 +668,7 @@ func (client *Client) Query(name string) *Query {
}
// AddTarget adds a target to the client, generating a unique ID for it.
func (client *Client) AddTarget(target Target) (id string, err error) {
func (client *Client) AddTarget(target Target) (err error) {
client.mutex.Lock()
defer client.mutex.Unlock()
@ -672,14 +682,11 @@ func (client *Client) AddTarget(target Target) (id string, err error) {
}
}
id = generateClientID("T")
client.targets = append(client.targets, target)
client.targetIds[target] = id
event := NewEvent("hook", "add_target")
event.Args = []string{client.targetIds[target], target.Kind(), target.Name()}
event.Args = []string{target.ID(), target.Kind(), target.Name()}
event.targets = []Target{target}
event.targetIds[target] = id
client.EmitNonBlocking(event)
return
@ -696,15 +703,14 @@ func (client *Client) RemoveTarget(target Target) (id string, err error) {
for i := range client.targets {
if target == client.targets[i] {
id = client.targetIds[target]
id = target.ID()
event := NewEvent("hook", "remove_target")
event.Args = []string{client.targetIds[target], target.Kind(), target.Name()}
event.Args = []string{target.ID(), target.Kind(), target.Name()}
client.EmitNonBlocking(event)
client.targets[i] = client.targets[len(client.targets)-1]
client.targets = client.targets[:len(client.targets)-1]
delete(client.targetIds, target)
// Ensure the channel has been parted
if channel, ok := target.(*Channel); ok && !channel.parted {
@ -1218,8 +1224,12 @@ func (client *Client) handleEvent(event *Event) {
var channel *Channel
if event.Nick == client.nick {
channel = &Channel{name: event.Arg(0), userlist: list.New(&client.isupport)}
_, _ = client.AddTarget(channel)
channel = &Channel{
id: generateClientID("T"),
name: event.Arg(0),
userlist: list.New(&client.isupport),
}
_ = client.AddTarget(channel)
} else {
channel = client.Channel(event.Arg(0))
}
@ -1317,14 +1327,20 @@ func (client *Client) handleEvent(event *Event) {
if targetName == client.nick {
target := client.Target("query", targetName)
if target == nil {
query := &Query{user: list.User{
Nick: event.Nick,
User: event.User,
Host: event.Host,
}}
query := &Query{
id: client.id,
user: list.User{
Nick: event.Nick,
User: event.User,
Host: event.Host,
},
}
if accountTag, ok := event.Tags["account"]; ok {
query.user.Account = accountTag
}
id, _ := client.AddTarget(query)
event.RenderTags["spawned"] = id
_ = client.AddTarget(query)
event.RenderTags["spawned"] = query.id
target = query
}
@ -1406,7 +1422,6 @@ func (client *Client) handleEvent(event *Event) {
channels = append(channels, channel.Name())
rejoinEvent.targets = append(rejoinEvent.targets, target)
rejoinEvent.targetIds[target] = client.targetIds[target]
}
}
client.mutex.RUnlock()
@ -1452,7 +1467,6 @@ func (client *Client) handleInTargets(nick string, event *Event) {
target.Handle(event, client)
event.targets = append(event.targets, target)
event.targetIds[target] = client.targetIds[target]
}
case *Query:
{
@ -1460,7 +1474,6 @@ func (client *Client) handleInTargets(nick string, event *Event) {
target.Handle(event, client)
event.targets = append(event.targets, target)
event.targetIds[target] = client.targetIds[target]
}
}
case *Status:
@ -1469,7 +1482,6 @@ func (client *Client) handleInTargets(nick string, event *Event) {
target.Handle(event, client)
event.targets = append(event.targets, target)
event.targetIds[target] = client.targetIds[target]
}
}
}
@ -1488,7 +1500,6 @@ func (client *Client) handleInTarget(target Target, event *Event) {
target.Handle(event, client)
event.targets = append(event.targets, target)
event.targetIds[target] = client.targetIds[target]
client.mutex.RUnlock()
}

2
cmd/ircrepl/main.go

@ -44,7 +44,7 @@ func main() {
err := client.Connect(*flagServer, *flagSsl)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to connect: %s", err)
_, _ = fmt.Fprintf(os.Stderr, "Failed to connect: %s", err)
os.Exit(1)
}

13
event.go

@ -27,8 +27,7 @@ type Event struct {
preventedDefault bool
hidden bool
targets []Target
targetIds map[Target]string
targets []Target
}
// NewEvent makes a new event with Kind, Verb, Time set and Args and Tags initialized.
@ -42,8 +41,6 @@ func NewEvent(kind, verb string) Event {
Args: make([]string, 0, 4),
Tags: make(map[string]string),
targetIds: make(map[Target]string),
RenderTags: make(map[string]string),
}
}
@ -92,7 +89,7 @@ func (event *Event) Context() context.Context {
// the current event handler returns.
//
// A use case for this is to prevent the default input handler from firing
// on an already prcoessed input event.
// on an already processed input event.
func (event *Event) PreventDefault() {
event.preventedDefault = true
}
@ -177,8 +174,8 @@ func (event *Event) StatusTarget() *Status {
func (event *Event) TargetIDs() []string {
ids := make([]string, len(event.targets))
for _, value := range event.targetIds {
ids = append(ids, value)
for _, target := range event.targets {
ids = append(ids, target.ID())
}
return ids
@ -202,7 +199,7 @@ func (event *Event) MarshalJSON() ([]byte, error) {
data.Targets = make([]string, 0, len(event.targets))
for _, target := range event.targets {
data.Targets = append(data.Targets, event.targetIds[target])
data.Targets = append(data.Targets, target.ID())
}
return json.Marshal(data)

6
query.go

@ -6,9 +6,15 @@ import (
// A Query is a target for direct messages to and from a specific nick.
type Query struct {
id string
user list.User
}
// ID returns a unique ID for the channel target.
func (query *Query) ID() string {
return query.id
}
// Kind returns "channel"
func (query *Query) Kind() string {
return "query"

6
status.go

@ -2,6 +2,12 @@ package irc
// A Status contains
type Status struct {
id string
}
// ID returns a unique ID for the status target.
func (status *Status) ID() string {
return status.id
}
// Kind returns "status"

1
target.go

@ -3,6 +3,7 @@ package irc
// A Target is a handler for a message meant for a limited part of the client, like a channel or
// query
type Target interface {
ID() string
Kind() string
Name() string
Handle(event *Event, client *Client)

Loading…
Cancel
Save