From 68b315345bc6336b3375989cb060b076462dc858 Mon Sep 17 00:00:00 2001 From: Artem Titoulenko Date: Sat, 18 Dec 2021 22:54:50 -0500 Subject: [PATCH] split out message delivery routine --- main.go | 62 +---------------------------- message_delivery_routine.go | 79 +++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 60 deletions(-) create mode 100644 message_delivery_routine.go diff --git a/main.go b/main.go index dd03783..838e2f3 100644 --- a/main.go +++ b/main.go @@ -74,66 +74,8 @@ func main() { defer listener.Close() // Goroutine that listens for messages to deliver and tries to find a user socket to push them to - commCh := make(chan *models.Message, 1) - go func() { - for { - message, more := <-commCh - if !more { - log.Printf("message delivery routine shutting down") - return - } - - log.Printf("got a message: %s", message) - if s, ok := sessions[message.To]; ok { - messageSnac := oscar.NewSNAC(4, 7) - messageSnac.Data.WriteUint64(message.MessageID) - messageSnac.Data.WriteUint16(1) - messageSnac.Data.WriteLPString(message.From) - messageSnac.Data.WriteUint16(0) // TODO: sender's warning level - - tlvs := []*oscar.TLV{ - oscar.NewTLV(1, util.Word(0x80)), // TODO: user class - oscar.NewTLV(6, util.Dword(0x0001|0x0100)), // TODO: user status - oscar.NewTLV(0xf, util.Dword(0)), // TODO: user idle time - oscar.NewTLV(3, util.Dword(0)), // TODO: user creation time - // oscar.NewTLV(4, []byte{}), // TODO: this TLV appears in automated responses like away messages - } - - // Length of TLVs in fixed part - messageSnac.Data.WriteUint16(uint16(len(tlvs))) - - // Write all of the TLVs to the SNAC - for _, tlv := range tlvs { - messageSnac.Data.WriteBinary(tlv) - } - - frag := oscar.Buffer{} - frag.Write([]byte{5, 1, 0, 4, 1, 1, 1, 1}) // TODO: first fragment [id, version, len, len, (cap * len)... ] - frag.Write([]byte{1, 1}) // message text fragment start (this is a busted "TLV") - frag.Write(util.Word(uint16(len(message.Contents) + 4))) // length of TLV - frag.Write([]byte{0, 0, 0, 0}) // TODO: message charset number, message charset subset - frag.WriteString(message.Contents) - - // Append the fragments - messageSnac.Data.Write(frag.Bytes()) - - messageFlap := oscar.NewFLAP(2) - messageFlap.Data.WriteBinary(messageSnac) - if err := s.Send(messageFlap); err != nil { - log.Panicf("could not deliver message %d: %s", message.MessageID, err.Error()) - continue - } else { - log.Printf("sent message %d to user %s at %s", message.MessageID, message.To, s.RemoteAddr()) - } - - if err := message.MarkDelivered(context.Background(), db); err != nil { - log.Panicf("could not mark message %d as delivered: %s", message.MessageID, err.Error()) - } - } else { - log.Printf("could not find session for user %s", message.To) - } - } - }() + commCh, messageRoutine := MessageDelivery() + go messageRoutine(db) handleCloseFn := func(ctx context.Context, session *oscar.Session) { log.Printf("%v disconnected", session.RemoteAddr()) diff --git a/message_delivery_routine.go b/message_delivery_routine.go new file mode 100644 index 0000000..1e8e153 --- /dev/null +++ b/message_delivery_routine.go @@ -0,0 +1,79 @@ +package main + +import ( + "aim-oscar/models" + "aim-oscar/oscar" + "aim-oscar/util" + "context" + "log" + + "github.com/uptrace/bun" +) + +type routineFn func(db *bun.DB) + +func MessageDelivery() (chan *models.Message, routineFn) { + commCh := make(chan *models.Message, 1) + + routine := func(db *bun.DB) { + for { + message, more := <-commCh + if !more { + log.Printf("message delivery routine shutting down") + return + } + + log.Printf("got a message: %s", message) + if s, ok := sessions[message.To]; ok { + messageSnac := oscar.NewSNAC(4, 7) + messageSnac.Data.WriteUint64(message.MessageID) + messageSnac.Data.WriteUint16(1) + messageSnac.Data.WriteLPString(message.From) + messageSnac.Data.WriteUint16(0) // TODO: sender's warning level + + tlvs := []*oscar.TLV{ + oscar.NewTLV(1, util.Word(0x80)), // TODO: user class + oscar.NewTLV(6, util.Dword(0x0001|0x0100)), // TODO: user status + oscar.NewTLV(0xf, util.Dword(0)), // TODO: user idle time + oscar.NewTLV(3, util.Dword(0)), // TODO: user creation time + // oscar.NewTLV(4, []byte{}), // TODO: this TLV appears in automated responses like away messages + } + + // Length of TLVs in fixed part + messageSnac.Data.WriteUint16(uint16(len(tlvs))) + + // Write all of the TLVs to the SNAC + for _, tlv := range tlvs { + messageSnac.Data.WriteBinary(tlv) + } + + frag := oscar.Buffer{} + frag.Write([]byte{5, 1, 0, 4, 1, 1, 1, 1}) // TODO: first fragment [id, version, len, len, (cap * len)... ] + frag.Write([]byte{1, 1}) // message text fragment start (this is a busted "TLV") + frag.Write(util.Word(uint16(len(message.Contents) + 4))) // length of TLV + frag.Write([]byte{0, 0, 0, 0}) // TODO: message charset number, message charset subset + frag.WriteString(message.Contents) + + // Append the fragments + messageSnac.Data.Write(frag.Bytes()) + + messageFlap := oscar.NewFLAP(2) + messageFlap.Data.WriteBinary(messageSnac) + if err := s.Send(messageFlap); err != nil { + log.Panicf("could not deliver message %d: %s", message.MessageID, err.Error()) + continue + } else { + log.Printf("sent message %d to user %s at %s", message.MessageID, message.To, s.RemoteAddr()) + } + + if err := message.MarkDelivered(context.Background(), db); err != nil { + log.Panicf("could not mark message %d as delivered: %s", message.MessageID, err.Error()) + } + } else { + log.Printf("could not find session for user %s", message.To) + } + } + } + + return commCh, routine +}