2018-08-23 00:12:26 +02:00
// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
2020-05-08 21:32:22 +02:00
// Copyright (C) 2020 Tulir Asokan
2018-08-23 00:12:26 +02:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package database
import (
2018-09-01 22:38:03 +02:00
"bytes"
2018-08-26 21:53:13 +02:00
"database/sql"
2018-09-01 22:38:03 +02:00
"encoding/json"
2021-02-09 22:41:14 +01:00
"strings"
2021-05-18 19:09:12 +02:00
"time"
2018-08-26 21:53:13 +02:00
2021-02-17 00:21:30 +01:00
"github.com/Rhymen/go-whatsapp"
2018-09-01 22:38:03 +02:00
waProto "github.com/Rhymen/go-whatsapp/binary/proto"
2019-01-11 20:17:31 +01:00
log "maunium.net/go/maulogger/v2"
2020-05-08 21:32:22 +02:00
"maunium.net/go/mautrix/id"
2018-08-23 00:12:26 +02:00
)
type MessageQuery struct {
db * Database
log log . Logger
}
func ( mq * MessageQuery ) New ( ) * Message {
return & Message {
db : mq . db ,
log : mq . log ,
}
}
2018-08-28 23:40:54 +02:00
func ( mq * MessageQuery ) GetAll ( chat PortalKey ) ( messages [ ] * Message ) {
2021-02-17 00:22:06 +01:00
rows , err := mq . db . Query ( "SELECT chat_jid, chat_receiver, jid, mxid, sender, timestamp, sent, content FROM message WHERE chat_jid=$1 AND chat_receiver=$2" , chat . JID , chat . Receiver )
2018-08-23 00:12:26 +02:00
if err != nil || rows == nil {
return nil
}
defer rows . Close ( )
for rows . Next ( ) {
messages = append ( messages , mq . New ( ) . Scan ( rows ) )
}
return
}
2021-02-17 00:21:30 +01:00
func ( mq * MessageQuery ) GetByJID ( chat PortalKey , jid whatsapp . MessageID ) * Message {
2021-02-17 00:22:06 +01:00
return mq . get ( "SELECT chat_jid, chat_receiver, jid, mxid, sender, timestamp, sent, content " +
2019-05-22 15:46:18 +02:00
"FROM message WHERE chat_jid=$1 AND chat_receiver=$2 AND jid=$3" , chat . JID , chat . Receiver , jid )
2018-08-23 00:12:26 +02:00
}
2020-05-08 21:32:22 +02:00
func ( mq * MessageQuery ) GetByMXID ( mxid id . EventID ) * Message {
2021-02-17 00:22:06 +01:00
return mq . get ( "SELECT chat_jid, chat_receiver, jid, mxid, sender, timestamp, sent, content " +
2019-05-22 15:46:18 +02:00
"FROM message WHERE mxid=$1" , mxid )
}
func ( mq * MessageQuery ) GetLastInChat ( chat PortalKey ) * Message {
2021-05-18 19:09:12 +02:00
return mq . GetLastInChatBefore ( chat , time . Now ( ) . Unix ( ) + 60 )
}
func ( mq * MessageQuery ) GetLastInChatBefore ( chat PortalKey , maxTimestamp int64 ) * Message {
2021-02-17 00:22:06 +01:00
msg := mq . get ( "SELECT chat_jid, chat_receiver, jid, mxid, sender, timestamp, sent, content " +
2021-05-18 19:09:12 +02:00
"FROM message WHERE chat_jid=$1 AND chat_receiver=$2 AND timestamp<=$3 AND sent=true ORDER BY timestamp DESC LIMIT 1" ,
chat . JID , chat . Receiver , maxTimestamp )
2019-05-22 22:05:58 +02:00
if msg == nil || msg . Timestamp == 0 {
2019-05-22 15:46:18 +02:00
// Old db, we don't know what the last message is.
return nil
}
return msg
2018-08-23 00:12:26 +02:00
}
func ( mq * MessageQuery ) get ( query string , args ... interface { } ) * Message {
row := mq . db . QueryRow ( query , args ... )
if row == nil {
return nil
}
return mq . New ( ) . Scan ( row )
}
type Message struct {
db * Database
log log . Logger
2019-05-22 15:46:18 +02:00
Chat PortalKey
2021-02-17 00:21:30 +01:00
JID whatsapp . MessageID
2020-05-08 21:32:22 +02:00
MXID id . EventID
2021-02-17 00:21:30 +01:00
Sender whatsapp . JID
2021-04-19 21:14:32 +02:00
Timestamp int64
2021-02-17 00:22:06 +01:00
Sent bool
2019-05-22 15:46:18 +02:00
Content * waProto . Message
2018-08-23 00:12:26 +02:00
}
2021-02-09 22:41:14 +01:00
func ( msg * Message ) IsFakeMXID ( ) bool {
return strings . HasPrefix ( msg . MXID . String ( ) , "net.maunium.whatsapp.fake::" )
}
2018-08-23 00:12:26 +02:00
func ( msg * Message ) Scan ( row Scannable ) * Message {
2018-09-01 22:38:03 +02:00
var content [ ] byte
2021-02-17 00:22:06 +01:00
err := row . Scan ( & msg . Chat . JID , & msg . Chat . Receiver , & msg . JID , & msg . MXID , & msg . Sender , & msg . Timestamp , & msg . Sent , & content )
2018-08-23 00:12:26 +02:00
if err != nil {
if err != sql . ErrNoRows {
2018-08-26 00:55:21 +02:00
msg . log . Errorln ( "Database scan failed:" , err )
2018-08-23 00:12:26 +02:00
}
return nil
}
2018-09-01 22:38:03 +02:00
2018-09-01 22:53:47 +02:00
msg . decodeBinaryContent ( content )
2018-09-01 22:38:03 +02:00
2018-08-23 00:12:26 +02:00
return msg
}
2018-09-01 22:53:47 +02:00
func ( msg * Message ) decodeBinaryContent ( content [ ] byte ) {
2018-09-01 22:38:03 +02:00
msg . Content = & waProto . Message { }
reader := bytes . NewReader ( content )
dec := json . NewDecoder ( reader )
err := dec . Decode ( msg . Content )
2018-08-23 00:12:26 +02:00
if err != nil {
2018-09-01 22:38:03 +02:00
msg . log . Warnln ( "Failed to decode message content:" , err )
2018-08-23 00:12:26 +02:00
}
}
2018-09-01 22:53:47 +02:00
func ( msg * Message ) encodeBinaryContent ( ) [ ] byte {
2018-09-01 22:38:03 +02:00
var buf bytes . Buffer
enc := json . NewEncoder ( & buf )
err := enc . Encode ( msg . Content )
if err != nil {
msg . log . Warnln ( "Failed to encode message content:" , err )
}
return buf . Bytes ( )
}
2019-01-21 22:55:16 +01:00
func ( msg * Message ) Insert ( ) {
2021-02-17 00:22:06 +01:00
_ , err := msg . db . Exec ( ` INSERT INTO message
( chat_jid , chat_receiver , jid , mxid , sender , timestamp , sent , content )
VALUES ( $ 1 , $ 2 , $ 3 , $ 4 , $ 5 , $ 6 , $ 7 , $ 8 ) ` ,
msg . Chat . JID , msg . Chat . Receiver , msg . JID , msg . MXID , msg . Sender , msg . Timestamp , msg . Sent , msg . encodeBinaryContent ( ) )
2018-08-23 00:12:26 +02:00
if err != nil {
2018-09-01 22:38:03 +02:00
msg . log . Warnfln ( "Failed to insert %s@%s: %v" , msg . Chat , msg . JID , err )
2018-08-23 00:12:26 +02:00
}
}
2019-05-16 00:59:36 +02:00
2021-02-17 00:22:06 +01:00
func ( msg * Message ) MarkSent ( ) {
msg . Sent = true
_ , err := msg . db . Exec ( "UPDATE message SET sent=true WHERE chat_jid=$1 AND chat_receiver=$2 AND jid=$3" , msg . Chat . JID , msg . Chat . Receiver , msg . JID )
if err != nil {
msg . log . Warnfln ( "Failed to update %s@%s: %v" , msg . Chat , msg . JID , err )
}
}
2019-05-16 00:59:36 +02:00
func ( msg * Message ) Delete ( ) {
_ , err := msg . db . Exec ( "DELETE FROM message WHERE chat_jid=$1 AND chat_receiver=$2 AND jid=$3" , msg . Chat . JID , msg . Chat . Receiver , msg . JID )
if err != nil {
msg . log . Warnfln ( "Failed to delete %s@%s: %v" , msg . Chat , msg . JID , err )
}
}