]>
nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/storage/recipients/CdsiStore.java
1170e6513f7d78569cd832656a91dcf124235161
1 package org
. asamk
. signal
. manager
. storage
. recipients
;
3 import org
. asamk
. signal
. manager
. storage
. Database
;
4 import org
. asamk
. signal
. manager
. storage
. Utils
;
6 import java
. sql
. Connection
;
7 import java
. sql
. SQLException
;
8 import java
. util
. HashSet
;
10 import java
. util
. stream
. Collectors
;
12 public class CdsiStore
{
14 private static final String TABLE_CDSI
= "cdsi" ;
16 private final Database database
;
18 public static void createSql ( Connection connection
) throws SQLException
{
19 // When modifying the CREATE statement here, also add a migration in AccountDatabase.java
20 try ( final var statement
= connection
. createStatement ()) {
21 statement
. executeUpdate ( """
23 _id INTEGER PRIMARY KEY,
24 number TEXT NOT NULL UNIQUE,
25 last_seen_at INTEGER NOT NULL
31 public CdsiStore ( final Database database
) {
32 this . database
= database
;
35 public Set
< String
> getAllNumbers () {
36 try ( final var connection
= database
. getConnection ()) {
37 return getAllNumbers ( connection
);
38 } catch ( SQLException e
) {
39 throw new RuntimeException ( "Failed read from cdsi store" , e
);
44 * Saves the set of e164 numbers used after a full refresh.
46 * @param fullNumbers All the e164 numbers used in the last CDS query (previous and new).
47 * @param seenNumbers The E164 numbers that were seen in either the system contacts or recipients table. This is different from fullNumbers in that fullNumbers
48 * includes every number we've ever seen, even if it's not in our contacts anymore.
50 public void updateAfterFullCdsQuery ( Set
< String
> fullNumbers
, Set
< String
> seenNumbers
) {
51 final var lastSeen
= System
. currentTimeMillis ();
52 try ( final var connection
= database
. getConnection ()) {
53 final var existingNumbers
= getAllNumbers ( connection
);
55 final var removedNumbers
= new HashSet
<>( existingNumbers
) {{
56 removeAll ( fullNumbers
);
58 removeNumbers ( connection
, removedNumbers
);
60 final var addedNumbers
= new HashSet
<>( fullNumbers
) {{
61 removeAll ( existingNumbers
);
63 addNumbers ( connection
, addedNumbers
, lastSeen
);
65 updateLastSeen ( connection
, seenNumbers
, lastSeen
);
66 } catch ( SQLException e
) {
67 throw new RuntimeException ( "Failed update cdsi store" , e
);
72 * Updates after a partial CDS query. Will not insert new entries.
73 * Instead, this will simply update the lastSeen timestamp of any entry we already have.
75 * @param seenNumbers The newly-added E164 numbers that we hadn't previously queried for.
77 public void updateAfterPartialCdsQuery ( Set
< String
> seenNumbers
) {
78 final var lastSeen
= System
. currentTimeMillis ();
80 try ( final var connection
= database
. getConnection ()) {
81 updateLastSeen ( connection
, seenNumbers
, lastSeen
);
82 } catch ( SQLException e
) {
83 throw new RuntimeException ( "Failed update cdsi store" , e
);
87 private static Set
< String
> getAllNumbers ( final Connection connection
) throws SQLException
{
93 ). formatted ( TABLE_CDSI
);
94 try ( final var statement
= connection
. prepareStatement ( sql
)) {
95 try ( var result
= Utils
. executeQueryForStream ( statement
, r
-> r
. getString ( "number" ))) {
96 return result
. collect ( Collectors
. toSet ());
101 private static void removeNumbers (
102 final Connection connection
, final Set
< String
> numbers
103 ) throws SQLException
{
109 ). formatted ( TABLE_CDSI
);
110 try ( final var statement
= connection
. prepareStatement ( sql
)) {
111 for ( final var number
: numbers
) {
112 statement
. setString ( 1 , number
);
113 statement
. executeUpdate ();
118 private static void addNumbers (
119 final Connection connection
, final Set
< String
> numbers
, final long lastSeen
120 ) throws SQLException
{
123 INSERT INTO %s (number, last_seen_at)
125 ON CONFLICT (number) DO UPDATE SET last_seen_at = excluded.last_seen_at
127 ). formatted ( TABLE_CDSI
);
128 try ( final var statement
= connection
. prepareStatement ( sql
)) {
129 for ( final var number
: numbers
) {
130 statement
. setString ( 1 , number
);
131 statement
. setLong ( 2 , lastSeen
);
132 statement
. executeUpdate ();
137 private static void updateLastSeen (
138 final Connection connection
, final Set
< String
> numbers
, final long lastSeen
139 ) throws SQLException
{
146 ). formatted ( TABLE_CDSI
);
147 try ( final var statement
= connection
. prepareStatement ( sql
)) {
148 for ( final var number
: numbers
) {
149 statement
. setLong ( 1 , lastSeen
);
150 statement
. setString ( 2 , number
);
151 statement
. executeUpdate ();
156 public void clearAll () {
161 ). formatted ( TABLE_CDSI
);
162 try ( final var connection
= database
. getConnection ()) {
163 try ( final var statement
= connection
. prepareStatement ( sql
)) {
164 statement
. executeUpdate ();
166 } catch ( SQLException e
) {
167 throw new RuntimeException ( "Failed update cdsi store" , e
);