]> git.r.bdr.sh - rbdr/mobius/blobdiff - hotline/transaction.go
More minor cleanup
[rbdr/mobius] / hotline / transaction.go
index 8fbdf35c0d652a71076c13fe776a625439c59c5c..b01fdfb112e8c6bb61922728cd0d879dabfb00e9 100644 (file)
@@ -1,72 +1,73 @@
 package hotline
 
 import (
+       "bytes"
        "encoding/binary"
        "errors"
        "fmt"
        "github.com/jhalter/mobius/concat"
        "math/rand"
-       "net"
 )
 
 const (
-       tranError          = 0
-       tranGetMsgs        = 101
-       tranNewMsg         = 102
-       tranOldPostNews    = 103
-       tranServerMsg      = 104
-       tranChatSend       = 105
-       tranChatMsg        = 106
-       tranLogin          = 107
-       tranSendInstantMsg = 108
-       tranShowAgreement  = 109
-       tranDisconnectUser = 110
-       // tranDisconnectMsg        = 111 TODO: implement friendly disconnect
-       tranInviteNewChat        = 112
-       tranInviteToChat         = 113
-       tranRejectChatInvite     = 114
-       tranJoinChat             = 115
-       tranLeaveChat            = 116
-       tranNotifyChatChangeUser = 117
-       tranNotifyChatDeleteUser = 118
-       tranNotifyChatSubject    = 119
-       tranSetChatSubject       = 120
-       tranAgreed               = 121
-       tranGetFileNameList      = 200
-       tranDownloadFile         = 202
-       tranUploadFile           = 203
-       tranNewFolder            = 205
-       tranDeleteFile           = 204
-       tranGetFileInfo          = 206
-       tranSetFileInfo          = 207
-       tranMoveFile             = 208
-       // tranMakeFileAlias        = 209 TODO: implement file alias command
-       tranDownloadFldr = 210
-       // tranDownloadInfo         = 211 TODO: implement file transfer queue
-       // tranDownloadBanner     = 212 TODO: figure out what this is used for
-       tranUploadFldr        = 213
-       tranGetUserNameList   = 300
-       tranNotifyChangeUser  = 301
-       tranNotifyDeleteUser  = 302
-       tranGetClientInfoText = 303
-       tranSetClientUserInfo = 304
-       tranListUsers         = 348
-       // tranUpdateUser         = 349 TODO: implement user updates from the > 1.5 account editor
-       tranNewUser            = 350
-       tranDeleteUser         = 351
-       tranGetUser            = 352
-       tranSetUser            = 353
-       tranUserAccess         = 354
-       tranUserBroadcast      = 355
-       tranGetNewsCatNameList = 370
-       tranGetNewsArtNameList = 371
-       tranDelNewsItem        = 380
-       tranNewNewsFldr        = 381
-       tranNewNewsCat         = 382
-       tranGetNewsArtData     = 400
-       tranPostNewsArt        = 410
-       tranDelNewsArt         = 411
-       tranKeepAlive          = 500
+       TranError                = 0
+       TranGetMsgs              = 101
+       TranNewMsg               = 102
+       TranOldPostNews          = 103
+       TranServerMsg            = 104
+       TranChatSend             = 105
+       TranChatMsg              = 106
+       TranLogin                = 107
+       TranSendInstantMsg       = 108
+       TranShowAgreement        = 109
+       TranDisconnectUser       = 110
+       TranDisconnectMsg        = 111 // TODO: implement server initiated friendly disconnect
+       TranInviteNewChat        = 112
+       TranInviteToChat         = 113
+       TranRejectChatInvite     = 114
+       TranJoinChat             = 115
+       TranLeaveChat            = 116
+       TranNotifyChatChangeUser = 117
+       TranNotifyChatDeleteUser = 118
+       TranNotifyChatSubject    = 119
+       TranSetChatSubject       = 120
+       TranAgreed               = 121
+       TranServerBanner         = 122
+       TranGetFileNameList      = 200
+       TranDownloadFile         = 202
+       TranUploadFile           = 203
+       TranNewFolder            = 205
+       TranDeleteFile           = 204
+       TranGetFileInfo          = 206
+       TranSetFileInfo          = 207
+       TranMoveFile             = 208
+       TranMakeFileAlias        = 209
+       TranDownloadFldr         = 210
+       TranDownloadInfo         = 211 // TODO: implement file transfer queue
+       TranDownloadBanner       = 212
+       TranUploadFldr           = 213
+       TranGetUserNameList      = 300
+       TranNotifyChangeUser     = 301
+       TranNotifyDeleteUser     = 302
+       TranGetClientInfoText    = 303
+       TranSetClientUserInfo    = 304
+       TranListUsers            = 348
+       TranUpdateUser           = 349
+       TranNewUser              = 350
+       TranDeleteUser           = 351
+       TranGetUser              = 352
+       TranSetUser              = 353
+       TranUserAccess           = 354
+       TranUserBroadcast        = 355
+       TranGetNewsCatNameList   = 370
+       TranGetNewsArtNameList   = 371
+       TranDelNewsItem          = 380
+       TranNewNewsFldr          = 381
+       TranNewNewsCat           = 382
+       TranGetNewsArtData       = 400
+       TranPostNewsArt          = 410
+       TranDelNewsArt           = 411
+       TranKeepAlive            = 500
 )
 
 type Transaction struct {
@@ -101,76 +102,53 @@ func NewTransaction(t int, clientID *[]byte, fields ...Field) *Transaction {
        }
 }
 
-// ReadTransaction parses a byte slice into a struct.  The input slice may be shorter or longer
-// that the transaction size depending on what was read from the network connection.
-func ReadTransaction(buf []byte) (*Transaction, int, error) {
-       totalSize := binary.BigEndian.Uint32(buf[12:16])
+// Write implements io.Writer interface for Transaction
+func (t *Transaction) Write(p []byte) (n int, err error) {
+       totalSize := binary.BigEndian.Uint32(p[12:16])
 
        // the buf may include extra bytes that are not part of the transaction
        // tranLen represents the length of bytes that are part of the transaction
        tranLen := int(20 + totalSize)
 
-       if tranLen > len(buf) {
-               return nil, 0, errors.New("buflen too small for tranLen")
+       if tranLen > len(p) {
+               return n, errors.New("buflen too small for tranLen")
        }
-       fields, err := ReadFields(buf[20:22], buf[22:tranLen])
+       fields, err := ReadFields(p[20:22], p[22:tranLen])
        if err != nil {
-               return nil, 0, err
+               return n, err
        }
 
-       return &Transaction{
-               Flags:      buf[0],
-               IsReply:    buf[1],
-               Type:       buf[2:4],
-               ID:         buf[4:8],
-               ErrorCode:  buf[8:12],
-               TotalSize:  buf[12:16],
-               DataSize:   buf[16:20],
-               ParamCount: buf[20:22],
-               Fields:     fields,
-       }, tranLen, nil
+       t.Flags = p[0]
+       t.IsReply = p[1]
+       t.Type = p[2:4]
+       t.ID = p[4:8]
+       t.ErrorCode = p[8:12]
+       t.TotalSize = p[12:16]
+       t.DataSize = p[16:20]
+       t.ParamCount = p[20:22]
+       t.Fields = fields
+
+       return len(p), err
 }
 
-func readN(conn net.Conn, n int) ([]Transaction, error) {
-       buf := make([]byte, 1400)
-       i := 0
-       for {
-               readLen, err := conn.Read(buf)
-               if err != nil {
-                       return nil, err
-               }
-
-               transactions, _, err := readTransactions(buf[:readLen])
-               //              spew.Fdump(os.Stderr, transactions)
-               if err != nil {
-                       return nil, err
-               }
+const tranHeaderLen = 20 // fixed length of transaction fields before the variable length fields
 
-               i += len(transactions)
-
-               if n == i {
-                       return transactions, nil
-               }
+// transactionScanner implements bufio.SplitFunc for parsing incoming byte slices into complete tokens
+func transactionScanner(data []byte, _ bool) (advance int, token []byte, err error) {
+       // The bytes that contain the size of a transaction are from 12:16, so we need at least 16 bytes
+       if len(data) < 16 {
+               return 0, nil, nil
        }
-}
 
-func readTransactions(buf []byte) ([]Transaction, int, error) {
-       var transactions []Transaction
+       totalSize := binary.BigEndian.Uint32(data[12:16])
 
-       bufLen := len(buf)
-
-       var bytesRead = 0
-       for bytesRead < bufLen {
-               t, tReadLen, err := ReadTransaction(buf[bytesRead:])
-               if err != nil {
-                       return transactions, bytesRead, err
-               }
-               bytesRead += tReadLen
-
-               transactions = append(transactions, *t)
+       // tranLen represents the length of bytes that are part of the transaction
+       tranLen := int(tranHeaderLen + totalSize)
+       if tranLen > len(data) {
+               return 0, nil, nil
        }
 
-       return transactions, bytesRead, nil
+       return tranLen, data[0:tranLen], nil
 }
 
 const minFieldLen = 4
@@ -214,7 +192,7 @@ func ReadFields(paramCount []byte, buf []byte) ([]Field, error) {
        return fields, nil
 }
 
-func (t Transaction) Payload() []byte {
+func (t *Transaction) MarshalBinary() (data []byte, err error) {
        payloadSize := t.Size()
 
        fieldCount := make([]byte, 2)
@@ -234,11 +212,11 @@ func (t Transaction) Payload() []byte {
                payloadSize, // this is the dataSize field, but seeming the same as totalSize
                fieldCount,
                fieldPayload,
-       )
+       ), err
 }
 
 // Size returns the total size of the transaction payload
-func (t Transaction) Size() []byte {
+func (t *Transaction) Size() []byte {
        bs := make([]byte, 4)
 
        fieldSize := 0
@@ -251,7 +229,7 @@ func (t Transaction) Size() []byte {
        return bs
 }
 
-func (t Transaction) GetField(id int) Field {
+func (t *Transaction) GetField(id int) Field {
        for _, field := range t.Fields {
                if id == int(binary.BigEndian.Uint16(field.ID)) {
                        return field
@@ -260,3 +238,7 @@ func (t Transaction) GetField(id int) Field {
 
        return Field{}
 }
+
+func (t *Transaction) IsError() bool {
+       return bytes.Equal(t.ErrorCode, []byte{0, 0, 0, 1})
+}