2020-11-18 09:16:51 +00:00
package communities
import (
2021-01-11 10:32:51 +00:00
"context"
2020-11-18 09:16:51 +00:00
"crypto/ecdsa"
"database/sql"
2021-01-11 10:32:51 +00:00
"errors"
2022-03-21 14:18:36 +00:00
"fmt"
2020-11-18 09:16:51 +00:00
"github.com/golang/protobuf/proto"
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/crypto"
2022-03-08 15:25:00 +00:00
"github.com/status-im/status-go/eth-node/types"
2021-01-11 10:32:51 +00:00
"github.com/status-im/status-go/protocol/common"
2020-11-18 09:16:51 +00:00
"github.com/status-im/status-go/protocol/protobuf"
)
type Persistence struct {
db * sql . DB
logger * zap . Logger
}
2021-11-11 16:37:04 +00:00
var ErrOldRequestToJoin = errors . New ( "old request to join" )
2022-08-22 10:10:31 +00:00
var ErrOldRequestToLeave = errors . New ( "old request to leave" )
2021-11-11 16:37:04 +00:00
2022-03-21 14:18:36 +00:00
const OR = " OR "
2022-09-20 19:57:39 +00:00
const communitiesBaseQuery = ` SELECT c.id, c.private_key, c.description,c.joined,c.spectated,c.verified,c.muted,r.clock FROM communities_communities c LEFT JOIN communities_requests_to_join r ON c.id = r.community_id AND r.public_key = ? `
2021-01-11 10:32:51 +00:00
2020-11-18 09:16:51 +00:00
func ( p * Persistence ) SaveCommunity ( community * Community ) error {
id := community . ID ( )
privateKey := community . PrivateKey ( )
description , err := community . ToBytes ( )
if err != nil {
return err
}
2022-09-20 19:57:39 +00:00
_ , err = p . db . Exec ( ` INSERT INTO communities_communities (id, private_key, description, joined, spectated, verified) VALUES (?, ?, ?, ?, ?, ?) ` , id , crypto . FromECDSA ( privateKey ) , description , community . config . Joined , community . config . Spectated , community . config . Verified )
2020-11-18 09:16:51 +00:00
return err
}
2022-06-01 07:55:48 +00:00
func ( p * Persistence ) ShouldHandleSyncCommunitySettings ( settings * protobuf . SyncCommunitySettings ) ( bool , error ) {
qr := p . db . QueryRow ( ` SELECT * FROM communities_settings WHERE community_id = ? AND clock > ? ` , settings . CommunityId , settings . Clock )
_ , err := p . scanRowToStruct ( qr . Scan )
switch err {
case sql . ErrNoRows :
// Query does not match, therefore clock value is not older than the new clock value or id was not found
return true , nil
case nil :
// Error is nil, therefore query matched and clock is older than the new clock
return false , nil
default :
// Error is not nil and is not sql.ErrNoRows, therefore pass out the error
return false , err
}
}
2021-08-06 15:40:23 +00:00
func ( p * Persistence ) ShouldHandleSyncCommunity ( community * protobuf . SyncCommunity ) ( bool , error ) {
// TODO see if there is a way to make this more elegant
// Keep the "*".
// When the test for this function fails because the table has changed we should update sync functionality
qr := p . db . QueryRow ( ` SELECT * FROM communities_communities WHERE id = ? AND synced_at > ? ` , community . Id , community . Clock )
_ , err := p . scanRowToStruct ( qr . Scan )
switch err {
case sql . ErrNoRows :
// Query does not match, therefore synced_at value is not older than the new clock value or id was not found
return true , nil
case nil :
// Error is nil, therefore query matched and synced_at is older than the new clock
return false , nil
default :
// Error is not nil and is not sql.ErrNoRows, therefore pass out the error
return false , err
}
}
2021-01-11 10:32:51 +00:00
func ( p * Persistence ) queryCommunities ( memberIdentity * ecdsa . PublicKey , query string ) ( response [ ] * Community , err error ) {
2020-11-18 09:16:51 +00:00
2021-01-11 10:32:51 +00:00
rows , err := p . db . Query ( query , common . PubkeyToHex ( memberIdentity ) )
2020-11-18 09:16:51 +00:00
if err != nil {
return nil , err
}
2020-12-22 11:00:13 +00:00
defer func ( ) {
if err != nil {
// Don't shadow original error
_ = rows . Close ( )
return
}
err = rows . Close ( )
} ( )
2020-11-18 09:16:51 +00:00
for rows . Next ( ) {
var publicKeyBytes , privateKeyBytes , descriptionBytes [ ] byte
2022-09-20 19:57:39 +00:00
var joined , spectated , verified , muted bool
2021-01-11 10:32:51 +00:00
var requestedToJoinAt sql . NullInt64
2022-09-20 19:57:39 +00:00
err := rows . Scan ( & publicKeyBytes , & privateKeyBytes , & descriptionBytes , & joined , & spectated , & verified , & muted , & requestedToJoinAt )
2020-11-18 09:16:51 +00:00
if err != nil {
return nil , err
}
2022-09-20 19:57:39 +00:00
org , err := unmarshalCommunityFromDB ( memberIdentity , publicKeyBytes , privateKeyBytes , descriptionBytes , joined , spectated , verified , muted , uint64 ( requestedToJoinAt . Int64 ) , p . logger )
2020-11-18 09:16:51 +00:00
if err != nil {
return nil , err
}
response = append ( response , org )
}
return response , nil
}
2021-01-11 10:32:51 +00:00
func ( p * Persistence ) AllCommunities ( memberIdentity * ecdsa . PublicKey ) ( [ ] * Community , error ) {
return p . queryCommunities ( memberIdentity , communitiesBaseQuery )
2020-11-18 09:16:51 +00:00
}
2021-01-11 10:32:51 +00:00
func ( p * Persistence ) JoinedCommunities ( memberIdentity * ecdsa . PublicKey ) ( [ ] * Community , error ) {
query := communitiesBaseQuery + ` WHERE c.joined `
return p . queryCommunities ( memberIdentity , query )
2020-11-18 09:16:51 +00:00
}
2022-09-20 19:57:39 +00:00
func ( p * Persistence ) SpectatedCommunities ( memberIdentity * ecdsa . PublicKey ) ( [ ] * Community , error ) {
query := communitiesBaseQuery + ` WHERE c.spectated `
return p . queryCommunities ( memberIdentity , query )
}
2022-04-11 16:14:08 +00:00
func ( p * Persistence ) rowsToCommunities ( memberIdentity * ecdsa . PublicKey , rows * sql . Rows ) ( comms [ ] * Community , err error ) {
2021-08-06 15:40:23 +00:00
defer func ( ) {
if err != nil {
// Don't shadow original error
_ = rows . Close ( )
return
}
err = rows . Close ( )
} ( )
for rows . Next ( ) {
var comm * Community
// Community specific fields
var publicKeyBytes , privateKeyBytes , descriptionBytes [ ] byte
2022-09-20 19:57:39 +00:00
var joined , spectated , verified , muted bool
2021-08-06 15:40:23 +00:00
// Request to join specific fields
var rtjID , rtjCommunityID [ ] byte
var rtjPublicKey , rtjENSName , rtjChatID sql . NullString
var rtjClock , rtjState sql . NullInt64
err = rows . Scan (
2022-09-20 19:57:39 +00:00
& publicKeyBytes , & privateKeyBytes , & descriptionBytes , & joined , & spectated , & verified , & muted ,
2021-08-06 15:40:23 +00:00
& rtjID , & rtjPublicKey , & rtjClock , & rtjENSName , & rtjChatID , & rtjCommunityID , & rtjState )
if err != nil {
return nil , err
}
2022-09-20 19:57:39 +00:00
comm , err = unmarshalCommunityFromDB ( memberIdentity , publicKeyBytes , privateKeyBytes , descriptionBytes , joined , spectated , verified , muted , uint64 ( rtjClock . Int64 ) , p . logger )
2021-08-06 15:40:23 +00:00
if err != nil {
return nil , err
}
rtj := unmarshalRequestToJoinFromDB ( rtjID , rtjCommunityID , rtjPublicKey , rtjENSName , rtjChatID , rtjClock , rtjState )
if ! rtj . Empty ( ) {
comm . AddRequestToJoin ( rtj )
}
comms = append ( comms , comm )
}
return comms , nil
}
2022-04-11 16:14:08 +00:00
func ( p * Persistence ) JoinedAndPendingCommunitiesWithRequests ( memberIdentity * ecdsa . PublicKey ) ( comms [ ] * Community , err error ) {
query := ` SELECT
2022-09-20 19:57:39 +00:00
c . id , c . private_key , c . description , c . joined , c . spectated , c . verified , c . muted ,
2022-04-11 16:14:08 +00:00
r . id , r . public_key , r . clock , r . ens_name , r . chat_id , r . community_id , r . state
FROM communities_communities c
LEFT JOIN communities_requests_to_join r ON c . id = r . community_id AND r . public_key = ?
WHERE c . Joined OR r . state = ? `
rows , err := p . db . Query ( query , common . PubkeyToHex ( memberIdentity ) , RequestToJoinStatePending )
if err != nil {
return nil , err
}
return p . rowsToCommunities ( memberIdentity , rows )
}
func ( p * Persistence ) DeletedCommunities ( memberIdentity * ecdsa . PublicKey ) ( comms [ ] * Community , err error ) {
query := ` SELECT
2022-09-20 19:57:39 +00:00
c . id , c . private_key , c . description , c . joined , c . spectated , c . verified , c . muted ,
2022-04-11 16:14:08 +00:00
r . id , r . public_key , r . clock , r . ens_name , r . chat_id , r . community_id , r . state
FROM communities_communities c
LEFT JOIN communities_requests_to_join r ON c . id = r . community_id AND r . public_key = ?
WHERE NOT c . Joined AND ( r . community_id IS NULL or r . state != ? ) `
rows , err := p . db . Query ( query , common . PubkeyToHex ( memberIdentity ) , RequestToJoinStatePending )
if err != nil {
return nil , err
}
return p . rowsToCommunities ( memberIdentity , rows )
}
2021-01-11 10:32:51 +00:00
func ( p * Persistence ) CreatedCommunities ( memberIdentity * ecdsa . PublicKey ) ( [ ] * Community , error ) {
query := communitiesBaseQuery + ` WHERE c.private_key IS NOT NULL `
return p . queryCommunities ( memberIdentity , query )
2020-11-18 09:16:51 +00:00
}
2021-01-11 10:32:51 +00:00
func ( p * Persistence ) GetByID ( memberIdentity * ecdsa . PublicKey , id [ ] byte ) ( * Community , error ) {
2020-11-18 09:16:51 +00:00
var publicKeyBytes , privateKeyBytes , descriptionBytes [ ] byte
var joined bool
2022-09-20 19:57:39 +00:00
var spectated bool
2020-11-18 09:16:51 +00:00
var verified bool
2021-06-30 13:29:43 +00:00
var muted bool
2021-01-11 10:32:51 +00:00
var requestedToJoinAt sql . NullInt64
2020-11-18 09:16:51 +00:00
2022-09-20 19:57:39 +00:00
err := p . db . QueryRow ( communitiesBaseQuery + ` WHERE c.id = ? ` , common . PubkeyToHex ( memberIdentity ) , id ) . Scan ( & publicKeyBytes , & privateKeyBytes , & descriptionBytes , & joined , & spectated , & verified , & muted , & requestedToJoinAt )
2020-11-18 09:16:51 +00:00
if err == sql . ErrNoRows {
return nil , nil
} else if err != nil {
return nil , err
}
2022-09-20 19:57:39 +00:00
return unmarshalCommunityFromDB ( memberIdentity , publicKeyBytes , privateKeyBytes , descriptionBytes , joined , spectated , verified , muted , uint64 ( requestedToJoinAt . Int64 ) , p . logger )
2020-11-18 09:16:51 +00:00
}
2022-09-20 19:57:39 +00:00
func unmarshalCommunityFromDB ( memberIdentity * ecdsa . PublicKey , publicKeyBytes , privateKeyBytes , descriptionBytes [ ] byte , joined , spectated , verified , muted bool , requestedToJoinAt uint64 , logger * zap . Logger ) ( * Community , error ) {
2020-11-18 09:16:51 +00:00
var privateKey * ecdsa . PrivateKey
var err error
if privateKeyBytes != nil {
privateKey , err = crypto . ToECDSA ( privateKeyBytes )
if err != nil {
return nil , err
}
}
metadata := & protobuf . ApplicationMetadataMessage { }
err = proto . Unmarshal ( descriptionBytes , metadata )
if err != nil {
return nil , err
}
description := & protobuf . CommunityDescription { }
err = proto . Unmarshal ( metadata . Payload , description )
if err != nil {
return nil , err
}
id , err := crypto . DecompressPubkey ( publicKeyBytes )
if err != nil {
return nil , err
}
config := Config {
PrivateKey : privateKey ,
CommunityDescription : description ,
2021-01-11 10:32:51 +00:00
MemberIdentity : memberIdentity ,
2020-11-18 09:16:51 +00:00
MarshaledCommunityDescription : descriptionBytes ,
Logger : logger ,
ID : id ,
Verified : verified ,
2021-06-30 13:29:43 +00:00
Muted : muted ,
2021-01-11 10:32:51 +00:00
RequestedToJoinAt : requestedToJoinAt ,
2020-11-18 09:16:51 +00:00
Joined : joined ,
2022-09-20 19:57:39 +00:00
Spectated : spectated ,
2020-11-18 09:16:51 +00:00
}
return New ( config )
}
2021-01-11 10:32:51 +00:00
2021-08-06 15:40:23 +00:00
func unmarshalRequestToJoinFromDB ( ID , communityID [ ] byte , publicKey , ensName , chatID sql . NullString , clock , state sql . NullInt64 ) * RequestToJoin {
return & RequestToJoin {
ID : ID ,
PublicKey : publicKey . String ,
Clock : uint64 ( clock . Int64 ) ,
ENSName : ensName . String ,
ChatID : chatID . String ,
CommunityID : communityID ,
State : RequestToJoinState ( state . Int64 ) ,
}
}
2021-01-11 10:32:51 +00:00
func ( p * Persistence ) SaveRequestToJoin ( request * RequestToJoin ) ( err error ) {
tx , err := p . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
var clock uint64
// Fetch any existing request to join
err = tx . QueryRow ( ` SELECT clock FROM communities_requests_to_join WHERE state = ? AND public_key = ? AND community_id = ? ` , RequestToJoinStatePending , request . PublicKey , request . CommunityID ) . Scan ( & clock )
if err != nil && err != sql . ErrNoRows {
return err
}
// This is already processed
if clock >= request . Clock {
2021-11-11 16:37:04 +00:00
return ErrOldRequestToJoin
2021-01-11 10:32:51 +00:00
}
_ , err = tx . Exec ( ` INSERT INTO communities_requests_to_join(id,public_key,clock,ens_name,chat_id,community_id,state) VALUES (?, ?, ?, ?, ?, ?, ?) ` , request . ID , request . PublicKey , request . Clock , request . ENSName , request . ChatID , request . CommunityID , request . State )
return err
}
2022-08-22 10:10:31 +00:00
func ( p * Persistence ) SaveRequestToLeave ( request * RequestToLeave ) error {
tx , err := p . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
var clock uint64
// Fetch any existing request to leave
err = tx . QueryRow ( ` SELECT clock FROM communities_requests_to_leave WHERE public_key = ? AND community_id = ? ` , request . PublicKey , request . CommunityID ) . Scan ( & clock )
if err != nil && err != sql . ErrNoRows {
return err
}
// This is already processed
if clock >= request . Clock {
return ErrOldRequestToLeave
}
_ , err = tx . Exec ( ` INSERT INTO communities_requests_to_leave(id,public_key,clock,community_id) VALUES (?, ?, ?, ?) ` , request . ID , request . PublicKey , request . Clock , request . CommunityID )
return err
}
2021-01-11 10:32:51 +00:00
func ( p * Persistence ) PendingRequestsToJoinForUser ( pk string ) ( [ ] * RequestToJoin , error ) {
var requests [ ] * RequestToJoin
rows , err := p . db . Query ( ` SELECT id,public_key,clock,ens_name,chat_id,community_id,state FROM communities_requests_to_join WHERE state = ? AND public_key = ? ` , RequestToJoinStatePending , pk )
if err != nil {
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
request := & RequestToJoin { }
err := rows . Scan ( & request . ID , & request . PublicKey , & request . Clock , & request . ENSName , & request . ChatID , & request . CommunityID , & request . State )
if err != nil {
return nil , err
}
requests = append ( requests , request )
}
return requests , nil
}
func ( p * Persistence ) HasPendingRequestsToJoinForUserAndCommunity ( userPk string , communityID [ ] byte ) ( bool , error ) {
var count int
err := p . db . QueryRow ( ` SELECT count(1) FROM communities_requests_to_join WHERE state = ? AND public_key = ? AND community_id = ? ` , RequestToJoinStatePending , userPk , communityID ) . Scan ( & count )
if err != nil {
return false , err
}
return count > 0 , nil
}
2022-08-04 07:44:35 +00:00
func ( p * Persistence ) RequestsToJoinForCommunityWithState ( id [ ] byte , state RequestToJoinState ) ( [ ] * RequestToJoin , error ) {
2021-01-11 10:32:51 +00:00
var requests [ ] * RequestToJoin
2022-08-04 07:44:35 +00:00
rows , err := p . db . Query ( ` SELECT id,public_key,clock,ens_name,chat_id,community_id,state FROM communities_requests_to_join WHERE state = ? AND community_id = ? ` , state , id )
2021-01-11 10:32:51 +00:00
if err != nil {
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
request := & RequestToJoin { }
err := rows . Scan ( & request . ID , & request . PublicKey , & request . Clock , & request . ENSName , & request . ChatID , & request . CommunityID , & request . State )
if err != nil {
return nil , err
}
requests = append ( requests , request )
}
return requests , nil
}
2022-08-04 07:44:35 +00:00
func ( p * Persistence ) PendingRequestsToJoinForCommunity ( id [ ] byte ) ( [ ] * RequestToJoin , error ) {
return p . RequestsToJoinForCommunityWithState ( id , RequestToJoinStatePending )
}
func ( p * Persistence ) DeclinedRequestsToJoinForCommunity ( id [ ] byte ) ( [ ] * RequestToJoin , error ) {
return p . RequestsToJoinForCommunityWithState ( id , RequestToJoinStateDeclined )
}
2021-08-06 15:40:23 +00:00
func ( p * Persistence ) SetRequestToJoinState ( pk string , communityID [ ] byte , state RequestToJoinState ) error {
2021-01-11 10:32:51 +00:00
_ , err := p . db . Exec ( ` UPDATE communities_requests_to_join SET state = ? WHERE community_id = ? AND public_key = ? ` , state , communityID , pk )
return err
}
2021-06-30 13:29:43 +00:00
func ( p * Persistence ) SetMuted ( communityID [ ] byte , muted bool ) error {
_ , err := p . db . Exec ( ` UPDATE communities_communities SET muted = ? WHERE id = ? ` , muted , communityID )
return err
}
2021-01-11 10:32:51 +00:00
func ( p * Persistence ) GetRequestToJoin ( id [ ] byte ) ( * RequestToJoin , error ) {
request := & RequestToJoin { }
err := p . db . QueryRow ( ` SELECT id,public_key,clock,ens_name,chat_id,community_id,state FROM communities_requests_to_join WHERE id = ? ` , id ) . Scan ( & request . ID , & request . PublicKey , & request . Clock , & request . ENSName , & request . ChatID , & request . CommunityID , & request . State )
if err != nil {
return nil , err
}
return request , nil
}
2021-08-06 15:40:23 +00:00
func ( p * Persistence ) SetSyncClock ( id [ ] byte , clock uint64 ) error {
_ , err := p . db . Exec ( ` UPDATE communities_communities SET synced_at = ? WHERE id = ? AND synced_at < ? ` , clock , id , clock )
return err
}
func ( p * Persistence ) SetPrivateKey ( id [ ] byte , privKey * ecdsa . PrivateKey ) error {
_ , err := p . db . Exec ( ` UPDATE communities_communities SET private_key = ? WHERE id = ? ` , crypto . FromECDSA ( privKey ) , id )
return err
}
2022-03-08 15:25:00 +00:00
2022-09-28 12:45:34 +00:00
func ( p * Persistence ) SaveWakuMessages ( messages [ ] * types . Message ) ( err error ) {
tx , err := p . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
query := ` INSERT OR REPLACE INTO waku_messages (sig, timestamp, topic, payload, padding, hash, third_party_id) VALUES (?, ?, ?, ?, ?, ?, ?) `
stmt , err := tx . Prepare ( query )
if err != nil {
return
}
defer stmt . Close ( )
for _ , msg := range messages {
_ , err = stmt . Exec (
msg . Sig ,
msg . Timestamp ,
msg . Topic . String ( ) ,
msg . Payload ,
msg . Padding ,
types . Bytes2Hex ( msg . Hash ) ,
msg . ThirdPartyID ,
)
if err != nil {
return
}
}
return
}
2022-03-09 09:58:05 +00:00
func ( p * Persistence ) SaveWakuMessage ( message * types . Message ) error {
2022-09-28 12:45:34 +00:00
_ , err := p . db . Exec ( ` INSERT OR REPLACE INTO waku_messages (sig, timestamp, topic, payload, padding, hash, third_party_id) VALUES (?, ?, ?, ?, ?, ?, ?) ` ,
2022-03-09 09:58:05 +00:00
message . Sig ,
message . Timestamp ,
message . Topic . String ( ) ,
message . Payload ,
message . Padding ,
types . Bytes2Hex ( message . Hash ) ,
2022-09-28 12:45:34 +00:00
message . ThirdPartyID ,
2022-03-09 09:58:05 +00:00
)
return err
}
2022-03-21 14:18:36 +00:00
func wakuMessageTimestampQuery ( topics [ ] types . TopicType ) string {
query := " FROM waku_messages WHERE "
for i , topic := range topics {
query += ` topic = " ` + topic . String ( ) + ` " `
if i < len ( topics ) - 1 {
query += OR
}
}
return query
}
func ( p * Persistence ) GetOldestWakuMessageTimestamp ( topics [ ] types . TopicType ) ( uint64 , error ) {
var timestamp sql . NullInt64
query := "SELECT MIN(timestamp)"
query += wakuMessageTimestampQuery ( topics )
err := p . db . QueryRow ( query ) . Scan ( & timestamp )
return uint64 ( timestamp . Int64 ) , err
}
func ( p * Persistence ) GetLatestWakuMessageTimestamp ( topics [ ] types . TopicType ) ( uint64 , error ) {
var timestamp sql . NullInt64
query := "SELECT MAX(timestamp)"
query += wakuMessageTimestampQuery ( topics )
err := p . db . QueryRow ( query ) . Scan ( & timestamp )
return uint64 ( timestamp . Int64 ) , err
}
func ( p * Persistence ) GetWakuMessagesByFilterTopic ( topics [ ] types . TopicType , from uint64 , to uint64 ) ( [ ] types . Message , error ) {
2022-09-28 12:45:34 +00:00
query := "SELECT sig, timestamp, topic, payload, padding, hash, third_party_id FROM waku_messages WHERE timestamp >= " + fmt . Sprint ( from ) + " AND timestamp < " + fmt . Sprint ( to ) + " AND ("
2022-03-21 14:18:36 +00:00
for i , topic := range topics {
query += ` topic = " ` + topic . String ( ) + ` " `
if i < len ( topics ) - 1 {
query += OR
}
}
query += ")"
rows , err := p . db . Query ( query )
if err != nil {
return nil , err
}
defer rows . Close ( )
messages := [ ] types . Message { }
for rows . Next ( ) {
msg := types . Message { }
var topicStr string
var hashStr string
2022-09-28 12:45:34 +00:00
err := rows . Scan ( & msg . Sig , & msg . Timestamp , & topicStr , & msg . Payload , & msg . Padding , & hashStr , & msg . ThirdPartyID )
2022-03-21 14:18:36 +00:00
if err != nil {
return nil , err
}
msg . Topic = types . StringToTopic ( topicStr )
msg . Hash = types . Hex2Bytes ( hashStr )
messages = append ( messages , msg )
}
return messages , nil
}
2022-04-22 07:42:22 +00:00
func ( p * Persistence ) HasCommunityArchiveInfo ( communityID types . HexBytes ) ( exists bool , err error ) {
err = p . db . QueryRow ( ` SELECT EXISTS(SELECT 1 FROM communities_archive_info WHERE community_id = ?) ` , communityID . String ( ) ) . Scan ( & exists )
return exists , err
}
2022-03-21 14:18:36 +00:00
func ( p * Persistence ) GetMagnetlinkMessageClock ( communityID types . HexBytes ) ( uint64 , error ) {
var magnetlinkClock uint64
err := p . db . QueryRow ( ` SELECT magnetlink_clock FROM communities_archive_info WHERE community_id = ? ` , communityID . String ( ) ) . Scan ( & magnetlinkClock )
if err == sql . ErrNoRows {
return 0 , nil
}
return magnetlinkClock , err
}
2022-04-22 07:42:22 +00:00
func ( p * Persistence ) SaveCommunityArchiveInfo ( communityID types . HexBytes , clock uint64 , lastArchiveEndDate uint64 ) error {
_ , err := p . db . Exec ( ` INSERT INTO communities_archive_info (magnetlink_clock, last_message_archive_end_date, community_id) VALUES (?, ?, ?) ` ,
clock ,
lastArchiveEndDate ,
communityID . String ( ) )
return err
}
2022-03-21 14:18:36 +00:00
func ( p * Persistence ) UpdateMagnetlinkMessageClock ( communityID types . HexBytes , clock uint64 ) error {
_ , err := p . db . Exec ( ` UPDATE communities_archive_info SET
magnetlink_clock = ?
WHERE community_id = ? ` ,
clock ,
communityID . String ( ) )
return err
}
func ( p * Persistence ) SaveLastMessageArchiveEndDate ( communityID types . HexBytes , endDate uint64 ) error {
_ , err := p . db . Exec ( ` INSERT INTO communities_archive_info (last_message_archive_end_date, community_id) VALUES (?, ?) ` ,
endDate ,
communityID . String ( ) )
return err
}
func ( p * Persistence ) UpdateLastMessageArchiveEndDate ( communityID types . HexBytes , endDate uint64 ) error {
_ , err := p . db . Exec ( ` UPDATE communities_archive_info SET
last_message_archive_end_date = ?
WHERE community_id = ? ` ,
endDate ,
communityID . String ( ) )
return err
}
func ( p * Persistence ) GetLastMessageArchiveEndDate ( communityID types . HexBytes ) ( uint64 , error ) {
var lastMessageArchiveEndDate uint64
err := p . db . QueryRow ( ` SELECT last_message_archive_end_date FROM communities_archive_info WHERE community_id = ? ` , communityID . String ( ) ) . Scan ( & lastMessageArchiveEndDate )
if err == sql . ErrNoRows {
return 0 , nil
} else if err != nil {
return 0 , err
}
return lastMessageArchiveEndDate , nil
}
2022-04-22 07:42:22 +00:00
func ( p * Persistence ) HasMessageArchiveID ( communityID types . HexBytes , hash string ) ( exists bool , err error ) {
err = p . db . QueryRow ( ` SELECT EXISTS (SELECT 1 FROM community_message_archive_hashes WHERE community_id = ? AND hash = ?) ` ,
communityID . String ( ) ,
hash ,
) . Scan ( & exists )
return exists , err
}
func ( p * Persistence ) SaveMessageArchiveID ( communityID types . HexBytes , hash string ) error {
_ , err := p . db . Exec ( ` INSERT INTO community_message_archive_hashes (community_id, hash) VALUES (?, ?) ` ,
communityID . String ( ) ,
hash ,
)
return err
}
2022-03-08 15:25:00 +00:00
func ( p * Persistence ) GetCommunitiesSettings ( ) ( [ ] CommunitySettings , error ) {
2022-06-01 07:55:48 +00:00
rows , err := p . db . Query ( "SELECT community_id, message_archive_seeding_enabled, message_archive_fetching_enabled, clock FROM communities_settings" )
2022-03-08 15:25:00 +00:00
if err != nil {
return nil , err
}
defer rows . Close ( )
communitiesSettings := [ ] CommunitySettings { }
for rows . Next ( ) {
settings := CommunitySettings { }
2022-06-01 07:55:48 +00:00
err := rows . Scan ( & settings . CommunityID , & settings . HistoryArchiveSupportEnabled , & settings . HistoryArchiveSupportEnabled , & settings . Clock )
2022-03-08 15:25:00 +00:00
if err != nil {
return nil , err
}
communitiesSettings = append ( communitiesSettings , settings )
}
return communitiesSettings , err
}
func ( p * Persistence ) CommunitySettingsExist ( communityID types . HexBytes ) ( bool , error ) {
var count int
err := p . db . QueryRow ( ` SELECT count(1) FROM communities_settings WHERE community_id = ? ` , communityID . String ( ) ) . Scan ( & count )
if err != nil {
return false , err
}
return count > 0 , nil
}
func ( p * Persistence ) GetCommunitySettingsByID ( communityID types . HexBytes ) ( * CommunitySettings , error ) {
settings := CommunitySettings { }
2022-06-01 07:55:48 +00:00
err := p . db . QueryRow ( ` SELECT community_id, message_archive_seeding_enabled, message_archive_fetching_enabled, clock FROM communities_settings WHERE community_id = ? ` , communityID . String ( ) ) . Scan ( & settings . CommunityID , & settings . HistoryArchiveSupportEnabled , & settings . HistoryArchiveSupportEnabled , & settings . Clock )
2022-03-08 15:25:00 +00:00
if err == sql . ErrNoRows {
return nil , nil
} else if err != nil {
return nil , err
}
return & settings , nil
}
func ( p * Persistence ) DeleteCommunitySettings ( communityID types . HexBytes ) error {
_ , err := p . db . Exec ( "DELETE FROM communities_settings WHERE community_id = ?" , communityID . String ( ) )
return err
}
func ( p * Persistence ) SaveCommunitySettings ( communitySettings CommunitySettings ) error {
_ , err := p . db . Exec ( ` INSERT INTO communities_settings (
community_id ,
message_archive_seeding_enabled ,
2022-06-01 07:55:48 +00:00
message_archive_fetching_enabled ,
clock
) VALUES ( ? , ? , ? , ? ) ` ,
2022-03-08 15:25:00 +00:00
communitySettings . CommunityID ,
communitySettings . HistoryArchiveSupportEnabled ,
communitySettings . HistoryArchiveSupportEnabled ,
2022-06-01 07:55:48 +00:00
communitySettings . Clock ,
2022-03-08 15:25:00 +00:00
)
return err
}
func ( p * Persistence ) UpdateCommunitySettings ( communitySettings CommunitySettings ) error {
_ , err := p . db . Exec ( ` UPDATE communities_settings SET
message_archive_seeding_enabled = ? ,
2022-06-01 07:55:48 +00:00
message_archive_fetching_enabled = ? ,
clock = ?
2022-03-08 15:25:00 +00:00
WHERE community_id = ? ` ,
communitySettings . HistoryArchiveSupportEnabled ,
communitySettings . HistoryArchiveSupportEnabled ,
2022-06-01 07:55:48 +00:00
communitySettings . Clock ,
2022-10-24 08:45:41 +00:00
communitySettings . CommunityID ,
2022-03-08 15:25:00 +00:00
)
return err
}
2022-03-21 14:18:36 +00:00
func ( p * Persistence ) GetCommunityChatIDs ( communityID types . HexBytes ) ( [ ] string , error ) {
rows , err := p . db . Query ( ` SELECT id FROM chats WHERE community_id = ? ` , communityID . String ( ) )
if err != nil {
return nil , err
}
defer rows . Close ( )
ids := [ ] string { }
for rows . Next ( ) {
id := ""
err := rows . Scan ( & id )
if err != nil {
return nil , err
}
ids = append ( ids , id )
}
return ids , nil
}