mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-14 07:59:31 +01:00
implement WHOWAS with a shared ringbuffer
This commit is contained in:
parent
41a6027d4e
commit
76852b0370
@ -225,6 +225,7 @@ func (client *Client) ChangeNickname(nickname string) {
|
|||||||
// Make reply before changing nick to capture original source id.
|
// Make reply before changing nick to capture original source id.
|
||||||
reply := RplNick(client, nickname)
|
reply := RplNick(client, nickname)
|
||||||
client.server.clients.Remove(client)
|
client.server.clients.Remove(client)
|
||||||
|
client.server.whoWas.Append(client)
|
||||||
client.nick = nickname
|
client.nick = nickname
|
||||||
client.server.clients.Add(client)
|
client.server.clients.Add(client)
|
||||||
for friend := range client.Friends() {
|
for friend := range client.Friends() {
|
||||||
@ -242,8 +243,8 @@ func (client *Client) Quit(message string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client.Reply(RplError("connection closed"))
|
client.Reply(RplError("connection closed"))
|
||||||
|
|
||||||
client.hasQuit = true
|
client.hasQuit = true
|
||||||
|
client.server.whoWas.Append(client)
|
||||||
friends := client.Friends()
|
friends := client.Friends()
|
||||||
friends.Remove(client)
|
friends.Remove(client)
|
||||||
client.destroy()
|
client.destroy()
|
||||||
|
@ -394,9 +394,10 @@ func (target *Client) RplTime() {
|
|||||||
"%s :%s", target.server.name, time.Now().Format(time.RFC1123))
|
"%s :%s", target.server.name, time.Now().Format(time.RFC1123))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (target *Client) RplWhoWasUser(nickname, username, hostname, realname string) {
|
func (target *Client) RplWhoWasUser(whoWas *WhoWas) {
|
||||||
target.NumericReply(RPL_WHOWASUSER,
|
target.NumericReply(RPL_WHOWASUSER,
|
||||||
"%s %s %s * :%s", nickname, username, hostname, realname)
|
"%s %s %s * :%s",
|
||||||
|
whoWas.nickname, whoWas.username, whoWas.hostname, whoWas.realname)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (target *Client) RplEndOfWhoWas(nickname string) {
|
func (target *Client) RplEndOfWhoWas(nickname string) {
|
||||||
|
@ -30,6 +30,7 @@ type Server struct {
|
|||||||
password []byte
|
password []byte
|
||||||
signals chan os.Signal
|
signals chan os.Signal
|
||||||
timeout chan *Client
|
timeout chan *Client
|
||||||
|
whoWas *WhoWasList
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(config *Config) *Server {
|
func NewServer(config *Config) *Server {
|
||||||
@ -46,6 +47,7 @@ func NewServer(config *Config) *Server {
|
|||||||
operators: config.Operators(),
|
operators: config.Operators(),
|
||||||
signals: make(chan os.Signal, 1),
|
signals: make(chan os.Signal, 1),
|
||||||
timeout: make(chan *Client, 16),
|
timeout: make(chan *Client, 16),
|
||||||
|
whoWas: NewWhoWasList(100),
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Server.Password != "" {
|
if config.Server.Password != "" {
|
||||||
@ -846,8 +848,14 @@ func (msg *KillCommand) HandleServer(server *Server) {
|
|||||||
func (msg *WhoWasCommand) HandleServer(server *Server) {
|
func (msg *WhoWasCommand) HandleServer(server *Server) {
|
||||||
client := msg.Client()
|
client := msg.Client()
|
||||||
for _, nickname := range msg.nicknames {
|
for _, nickname := range msg.nicknames {
|
||||||
// TODO implement nick history
|
results := server.whoWas.Find(nickname, msg.count)
|
||||||
client.ErrWasNoSuchNick(nickname)
|
if len(results) == 0 {
|
||||||
|
client.ErrWasNoSuchNick(nickname)
|
||||||
|
} else {
|
||||||
|
for _, whoWas := range results {
|
||||||
|
client.RplWhoWasUser(whoWas)
|
||||||
|
}
|
||||||
|
}
|
||||||
client.RplEndOfWhoWas(nickname)
|
client.RplEndOfWhoWas(nickname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
73
irc/whowas.go
Normal file
73
irc/whowas.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package irc
|
||||||
|
|
||||||
|
type WhoWasList struct {
|
||||||
|
buffer []*WhoWas
|
||||||
|
start uint
|
||||||
|
end uint
|
||||||
|
}
|
||||||
|
|
||||||
|
type WhoWas struct {
|
||||||
|
nickname string
|
||||||
|
username string
|
||||||
|
hostname string
|
||||||
|
realname string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWhoWasList(size uint) *WhoWasList {
|
||||||
|
return &WhoWasList{
|
||||||
|
buffer: make([]*WhoWas, size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (list *WhoWasList) Append(client *Client) {
|
||||||
|
list.buffer[list.end] = &WhoWas{
|
||||||
|
nickname: client.Nick(),
|
||||||
|
username: client.username,
|
||||||
|
hostname: client.hostname,
|
||||||
|
realname: client.realname,
|
||||||
|
}
|
||||||
|
list.end = (list.end + 1) % uint(len(list.buffer))
|
||||||
|
if list.end == list.start {
|
||||||
|
list.start = (list.end + 1) % uint(len(list.buffer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (list *WhoWasList) Find(nickname string, limit int64) []*WhoWas {
|
||||||
|
results := make([]*WhoWas, 0)
|
||||||
|
for whoWas := range list.Each() {
|
||||||
|
if nickname != whoWas.nickname {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
results = append(results, whoWas)
|
||||||
|
if int64(len(results)) >= limit {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
func (list *WhoWasList) prev(index uint) uint {
|
||||||
|
index -= 1
|
||||||
|
if index < 0 {
|
||||||
|
index += uint(len(list.buffer))
|
||||||
|
}
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate the buffer in reverse.
|
||||||
|
func (list *WhoWasList) Each() <-chan *WhoWas {
|
||||||
|
ch := make(chan *WhoWas)
|
||||||
|
go func() {
|
||||||
|
defer close(ch)
|
||||||
|
if list.start == list.end {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
start := list.prev(list.end)
|
||||||
|
end := list.prev(list.start)
|
||||||
|
for start != end {
|
||||||
|
ch <- list.buffer[start]
|
||||||
|
start = list.prev(start)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return ch
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user