diff options
author | Hubert Hirtz <hubert@hirtzfr.eu> | 2020-06-13 18:05:55 +0200 |
---|---|---|
committer | Hubert Hirtz <hubert@hirtzfr.eu> | 2020-06-13 18:05:55 +0200 |
commit | 3d338eedc522d2fd1d913b0de12c13ad7187daeb (patch) | |
tree | 6a44ce3f87eb79a08784de3461d8b906fbf2d6f0 /irc | |
parent | Don't scroll past buffer content (diff) |
draft/chathistory support???
Diffstat (limited to 'irc')
-rw-r--r-- | irc/events.go | 5 | ||||
-rw-r--r-- | irc/states.go | 127 | ||||
-rw-r--r-- | irc/tokens.go | 23 |
3 files changed, 117 insertions, 38 deletions
diff --git a/irc/events.go b/irc/events.go index 96bf786..66237e9 100644 --- a/irc/events.go +++ b/irc/events.go @@ -61,3 +61,8 @@ type ChannelMessageEvent struct { Content string Time time.Time } + +type HistoryEvent struct { + Target string + Messages []Event +} diff --git a/irc/states.go b/irc/states.go index c25bda6..6363ae8 100644 --- a/irc/states.go +++ b/irc/states.go @@ -47,6 +47,7 @@ var SupportedCapabilities = map[string]struct{}{ "away-notify": {}, "batch": {}, "cap-notify": {}, + "draft/chathistory": {}, "echo-message": {}, "extended-join": {}, "invite-notify": {}, @@ -92,7 +93,7 @@ type ( } actionPrivMsg struct { - Channel string + Target string Content string } @@ -102,6 +103,11 @@ type ( actionTypingStop struct { Channel string } + + actionRequestHistory struct { + Target string + Before time.Time + } ) type SessionParams struct { @@ -137,16 +143,17 @@ type Session struct { enabledCaps map[string]struct{} features map[string]string - users map[string]User - channels map[string]Channel + users map[string]User + channels map[string]Channel + chBatches map[string]HistoryEvent } func NewSession(conn io.ReadWriteCloser, params SessionParams) (s Session, err error) { s = Session{ conn: conn, - msgs: make(chan Message, 128), - acts: make(chan action, 128), - evts: make(chan Event, 128), + msgs: make(chan Message, 16), + acts: make(chan action, 16), + evts: make(chan Event, 16), typingStamps: map[string]time.Time{}, nick: params.Nickname, lNick: strings.ToLower(params.Nickname), @@ -158,6 +165,7 @@ func NewSession(conn io.ReadWriteCloser, params SessionParams) (s Session, err e features: map[string]string{}, users: map[string]User{}, channels: map[string]Channel{}, + chBatches: map[string]HistoryEvent{}, } s.running.Store(true) @@ -230,12 +238,12 @@ func (s *Session) part(act actionPart) (err error) { return } -func (s *Session) PrivMsg(channel, content string) { - s.acts <- actionPrivMsg{channel, content} +func (s *Session) PrivMsg(target, content string) { + s.acts <- actionPrivMsg{target, content} } func (s *Session) privMsg(act actionPrivMsg) (err error) { - err = s.send("PRIVMSG %s :%s\r\n", act.Channel, act.Content) + err = s.send("PRIVMSG %s :%s\r\n", act.Target, act.Content) return } @@ -261,8 +269,8 @@ func (s *Session) typing(act actionTyping) (err error) { return } -func (s *Session) TypingStop(to string) { - s.acts <- actionTypingStop{to} +func (s *Session) TypingStop(channel string) { + s.acts <- actionTypingStop{channel} } func (s *Session) typingStop(act actionTypingStop) (err error) { @@ -274,6 +282,21 @@ func (s *Session) typingStop(act actionTypingStop) (err error) { return } +func (s *Session) RequestHistory(target string, before time.Time) { + s.acts <- actionRequestHistory{target, before} +} + +func (s *Session) requestHistory(act actionRequestHistory) (err error) { + if _, ok := s.enabledCaps["draft/chathistory"]; !ok { + return + } + + t := act.Before + err = s.send("CHATHISTORY BEFORE %s timestamp=%04d-%02d-%02dT%02d:%02d:%02d.%03dZ 100\r\n", act.Target, t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond()/1e6) + + return +} + func (s *Session) run() { for s.Running() { var ( @@ -294,6 +317,8 @@ func (s *Session) run() { err = s.typing(act) case actionTypingStop: err = s.typingStop(act) + case actionRequestHistory: + err = s.requestHistory(act) } case msg := <-s.msgs: if s.state == ConnStart { @@ -415,6 +440,16 @@ func (s *Session) handleStart(msg Message) (ev Event, err error) { } func (s *Session) handle(msg Message) (ev Event, err error) { + if id, ok := msg.Tags["batch"]; ok { + if b, ok := s.chBatches[id]; ok { + s.chBatches[id] = HistoryEvent{ + Target: b.Target, + Messages: append(b.Messages, s.privmsgToEvent(msg)), + } + return + } + } + switch msg.Command { case "001": // RPL_WELCOME s.nick = msg.Params[0] @@ -608,33 +643,19 @@ func (s *Session) handle(msg Message) (ev Event, err error) { c.Topic = msg.Params[2] } case "PRIVMSG": - nick, _, _ := FullMask(msg.Prefix) - target := strings.ToLower(msg.Params[0]) - - if target == s.lNick { - // PRIVMSG to self - t, ok := msg.Time() - if !ok { - t = time.Now() - } - ev = QueryMessageEvent{ - UserEvent: UserEvent{Nick: nick}, - Content: msg.Params[1], - Time: t, - } - } else if _, ok := s.channels[target]; ok { - // PRIVMSG to channel - t, ok := msg.Time() - if !ok { - t = time.Now() - } - ev = ChannelMessageEvent{ - UserEvent: UserEvent{Nick: nick}, - ChannelEvent: ChannelEvent{Channel: msg.Params[0]}, - Content: msg.Params[1], - Time: t, - } + ev = s.privmsgToEvent(msg) + case "BATCH": + batchStart := msg.Params[0][0] == '+' + id := msg.Params[0][1:] + + if batchStart && msg.Params[1] == "chathistory" { + s.chBatches[id] = HistoryEvent{Target: msg.Params[2]} + } else if b, ok := s.chBatches[id]; ok { + ev = b + delete(s.chBatches, id) } + case "FAIL": + fmt.Println("FAIL", msg.Params) case "PING": err = s.send("PONG :%s\r\n", msg.Params[0]) if err != nil { @@ -651,6 +672,38 @@ func (s *Session) handle(msg Message) (ev Event, err error) { return } +func (s *Session) privmsgToEvent(msg Message) (ev Event) { + nick, _, _ := FullMask(msg.Prefix) + target := strings.ToLower(msg.Params[0]) + + if target == s.lNick { + // PRIVMSG to self + t, ok := msg.Time() + if !ok { + t = time.Now() + } + ev = QueryMessageEvent{ + UserEvent: UserEvent{Nick: nick}, + Content: msg.Params[1], + Time: t, + } + } else if _, ok := s.channels[target]; ok { + // PRIVMSG to channel + t, ok := msg.Time() + if !ok { + t = time.Now() + } + ev = ChannelMessageEvent{ + UserEvent: UserEvent{Nick: nick}, + ChannelEvent: ChannelEvent{Channel: msg.Params[0]}, + Content: msg.Params[1], + Time: t, + } + } + + return +} + func (s *Session) updateFeatures(features []string) { for _, f := range features { if f == "" || f == "-" || f == "=" || f == "-=" { diff --git a/irc/tokens.go b/irc/tokens.go index 3d9a034..b282488 100644 --- a/irc/tokens.go +++ b/irc/tokens.go @@ -90,6 +90,7 @@ var ( ) var ( + errEmptyBatchID = errors.New("empty BATCH ID") errNoPrefix = errors.New("missing prefix") errNotEnoughParams = errors.New("not enough params") errUnknownCommand = errors.New("unknown command") @@ -223,6 +224,26 @@ func (msg *Message) Validate() (err error) { if len(msg.Params) < 2 { err = errNotEnoughParams } + case "BATCH": + if len(msg.Params) < 1 { + err = errNotEnoughParams + break + } + if len(msg.Params[0]) < 2 { + err = errEmptyBatchID + break + } + if msg.Params[0][0] == '+' { + if len(msg.Params) < 2 { + err = errNotEnoughParams + break + } + if msg.Params[1] == "chathistory" && len(msg.Params) < 3 { + err = errNotEnoughParams + } + } else if msg.Params[0][0] != '-' { + err = errEmptyBatchID + } case "PING": if len(msg.Params) < 1 { err = errNotEnoughParams @@ -253,7 +274,7 @@ func (msg *Message) Time() (t time.Time, ok bool) { return } - t = time.Date(year, time.Month(month), day, hour, minute, second, millis*1000000, time.UTC) + t = time.Date(year, time.Month(month), day, hour, minute, second, millis*1e6, time.UTC) t = t.Local() return |