Skip to content

Commit 55dfcc0

Browse files
committed
Multi-server rendezvous
1 parent ebb8825 commit 55dfcc0

File tree

13 files changed

+382
-257
lines changed

13 files changed

+382
-257
lines changed

pkg/code/data/internal.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,10 @@ type DatabaseData interface {
225225

226226
// Rendezvous
227227
// --------------------------------------------------------------------------------
228-
SaveRendezvous(ctx context.Context, record *rendezvous.Record) error
228+
PutRendezvous(ctx context.Context, record *rendezvous.Record) error
229+
ExtendRendezvousExpiry(ctx context.Context, key, address string, expiry time.Time) error
230+
DeleteRendezvous(ctx context.Context, key, address string) error
229231
GetRendezvous(ctx context.Context, key string) (*rendezvous.Record, error)
230-
DeleteRendezvous(ctx context.Context, key string) error
231232

232233
// Requests
233234
// --------------------------------------------------------------------------------
@@ -846,15 +847,18 @@ func (dp *DatabaseProvider) GetTotalExternalDepositedAmountInUsd(ctx context.Con
846847

847848
// Rendezvous
848849
// --------------------------------------------------------------------------------
849-
func (dp *DatabaseProvider) SaveRendezvous(ctx context.Context, record *rendezvous.Record) error {
850-
return dp.rendezvous.Save(ctx, record)
850+
func (dp *DatabaseProvider) PutRendezvous(ctx context.Context, record *rendezvous.Record) error {
851+
return dp.rendezvous.Put(ctx, record)
852+
}
853+
func (dp *DatabaseProvider) ExtendRendezvousExpiry(ctx context.Context, key, address string, expiry time.Time) error {
854+
return dp.rendezvous.ExtendExpiry(ctx, key, address, expiry)
855+
}
856+
func (dp *DatabaseProvider) DeleteRendezvous(ctx context.Context, key, address string) error {
857+
return dp.rendezvous.Delete(ctx, key, address)
851858
}
852859
func (dp *DatabaseProvider) GetRendezvous(ctx context.Context, key string) (*rendezvous.Record, error) {
853860
return dp.rendezvous.Get(ctx, key)
854861
}
855-
func (dp *DatabaseProvider) DeleteRendezvous(ctx context.Context, key string) error {
856-
return dp.rendezvous.Delete(ctx, key)
857-
}
858862

859863
// Payment Request
860864
// --------------------------------------------------------------------------------

pkg/code/data/rendezvous/memory/store.go

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ func New() rendezvous.Store {
1919
return &store{}
2020
}
2121

22-
// Save implements rendezvous.Store.Save
23-
func (s *store) Save(_ context.Context, data *rendezvous.Record) error {
22+
// Put implements rendezvous.Store.Put
23+
func (s *store) Put(_ context.Context, data *rendezvous.Record) error {
2424
if err := data.Validate(); err != nil {
2525
return err
2626
}
@@ -30,16 +30,21 @@ func (s *store) Save(_ context.Context, data *rendezvous.Record) error {
3030

3131
s.last++
3232
if item := s.find(data); item != nil {
33-
item.Location = data.Location
34-
item.LastUpdatedAt = time.Now()
33+
if item.ExpiresAt.After(time.Now()) {
34+
return rendezvous.ErrExists
35+
}
36+
37+
item.Address = data.Address
38+
item.ExpiresAt = data.ExpiresAt
3539

3640
item.CopyTo(data)
3741
} else {
3842
if data.Id == 0 {
3943
data.Id = s.last
4044
}
41-
data.CreatedAt = time.Now()
42-
data.LastUpdatedAt = time.Now()
45+
if data.CreatedAt.IsZero() {
46+
data.CreatedAt = time.Now()
47+
}
4348

4449
cloned := data.Clone()
4550
s.records = append(s.records, &cloned)
@@ -48,27 +53,32 @@ func (s *store) Save(_ context.Context, data *rendezvous.Record) error {
4853
return nil
4954
}
5055

51-
// Get implements rendezvous.Store.Get
52-
func (s *store) Get(_ context.Context, key string) (*rendezvous.Record, error) {
56+
// ExtendExpiry implements rendezvous.Store.ExtendExpiry
57+
func (s *store) ExtendExpiry(_ context.Context, key, address string, expiry time.Time) error {
5358
s.mu.Lock()
5459
defer s.mu.Unlock()
5560

56-
item := s.findByKey(key)
61+
item := s.findByKeyAndAddress(key, address)
5762
if item == nil {
58-
return nil, rendezvous.ErrNotFound
63+
return rendezvous.ErrNotFound
5964
}
6065

61-
cloned := item.Clone()
62-
return &cloned, nil
66+
if item.ExpiresAt.Before(time.Now()) {
67+
return rendezvous.ErrNotFound
68+
}
69+
70+
item.ExpiresAt = expiry
71+
72+
return nil
6373
}
6474

6575
// Delete implements rendezvous.Store.Delete
66-
func (s *store) Delete(_ context.Context, key string) error {
76+
func (s *store) Delete(_ context.Context, key, address string) error {
6777
s.mu.Lock()
6878
defer s.mu.Unlock()
6979

7080
for i, item := range s.records {
71-
if item.Key == key {
81+
if item.Key == key && item.Address == address {
7282
s.records = append(s.records[:i], s.records[i+1:]...)
7383
return nil
7484
}
@@ -77,6 +87,24 @@ func (s *store) Delete(_ context.Context, key string) error {
7787
return nil
7888
}
7989

90+
// Get implements rendezvous.Store.Get
91+
func (s *store) Get(_ context.Context, key string) (*rendezvous.Record, error) {
92+
s.mu.Lock()
93+
defer s.mu.Unlock()
94+
95+
item := s.findByKey(key)
96+
if item == nil {
97+
return nil, rendezvous.ErrNotFound
98+
}
99+
100+
if item.ExpiresAt.Before(time.Now()) {
101+
return nil, rendezvous.ErrNotFound
102+
}
103+
104+
cloned := item.Clone()
105+
return &cloned, nil
106+
}
107+
80108
func (s *store) find(data *rendezvous.Record) *rendezvous.Record {
81109
for _, item := range s.records {
82110
if item.Id == data.Id {
@@ -101,6 +129,16 @@ func (s *store) findByKey(key string) *rendezvous.Record {
101129
return nil
102130
}
103131

132+
func (s *store) findByKeyAndAddress(key, address string) *rendezvous.Record {
133+
for _, item := range s.records {
134+
if item.Key == key && item.Address == address {
135+
return item
136+
}
137+
}
138+
139+
return nil
140+
}
141+
104142
func (s *store) reset() {
105143
s.mu.Lock()
106144
defer s.mu.Unlock()

pkg/code/data/rendezvous/postgres/model.go

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,20 @@ import (
77

88
"github.com/jmoiron/sqlx"
99

10-
pgutil "github.com/code-payments/code-server/pkg/database/postgres"
1110
"github.com/code-payments/code-server/pkg/code/data/rendezvous"
11+
pgutil "github.com/code-payments/code-server/pkg/database/postgres"
1212
)
1313

1414
const (
1515
tableName = "codewallet__core_rendezvous"
1616
)
1717

1818
type model struct {
19-
Id sql.NullInt64 `db:"id"`
20-
Key string `db:"key"`
21-
Location string `db:"location"`
22-
CreatedAt time.Time `db:"created_at"`
23-
LastUpdatedAt time.Time `db:"last_updated_at"`
19+
Id sql.NullInt64 `db:"id"`
20+
Key string `db:"key"`
21+
Address string `db:"address"`
22+
CreatedAt time.Time `db:"created_at"`
23+
ExpiresAt time.Time `db:"expires_at"`
2424
}
2525

2626
func toModel(obj *rendezvous.Record) (*model, error) {
@@ -29,69 +29,93 @@ func toModel(obj *rendezvous.Record) (*model, error) {
2929
}
3030

3131
return &model{
32-
Key: obj.Key,
33-
Location: obj.Location,
34-
CreatedAt: obj.CreatedAt,
35-
LastUpdatedAt: obj.LastUpdatedAt,
32+
Key: obj.Key,
33+
Address: obj.Address,
34+
CreatedAt: obj.CreatedAt,
35+
ExpiresAt: obj.ExpiresAt,
3636
}, nil
3737
}
3838

3939
func fromModel(obj *model) *rendezvous.Record {
4040
return &rendezvous.Record{
41-
Id: uint64(obj.Id.Int64),
42-
Key: obj.Key,
43-
Location: obj.Location,
44-
CreatedAt: obj.CreatedAt,
45-
LastUpdatedAt: obj.LastUpdatedAt,
41+
Id: uint64(obj.Id.Int64),
42+
Key: obj.Key,
43+
Address: obj.Address,
44+
CreatedAt: obj.CreatedAt,
45+
ExpiresAt: obj.ExpiresAt,
4646
}
4747
}
4848

49-
func (m *model) dbSave(ctx context.Context, db *sqlx.DB) error {
49+
func (m *model) dbPut(ctx context.Context, db *sqlx.DB) error {
5050
query := `INSERT INTO ` + tableName + `
51-
(key, location, created_at, last_updated_at)
51+
(key, address, created_at, expires_at)
5252
VALUES ($1, $2, $3, $4)
5353
5454
ON CONFLICT (key)
5555
DO UPDATE
56-
SET location = $2, last_updated_at = $4
57-
WHERE ` + tableName + `.key = $1
56+
SET address = $2, expires_at = $4
57+
WHERE ` + tableName + `.key = $1 AND ` + tableName + `.expires_at < NOW()
5858
59-
RETURNING id, key, location, created_at, last_updated_at
59+
RETURNING id, key, address, created_at, expires_at
6060
`
6161

6262
if m.CreatedAt.IsZero() {
6363
m.CreatedAt = time.Now()
6464
}
65-
m.LastUpdatedAt = time.Now()
6665

67-
return db.QueryRowxContext(
66+
err := db.QueryRowxContext(
6867
ctx,
6968
query,
7069
m.Key,
71-
m.Location,
70+
m.Address,
7271
m.CreatedAt,
73-
m.LastUpdatedAt,
72+
m.ExpiresAt,
7473
).StructScan(m)
74+
75+
if err != nil {
76+
return pgutil.CheckNoRows(err, rendezvous.ErrExists)
77+
}
78+
79+
return nil
7580
}
7681

77-
func dbGetByKey(ctx context.Context, db *sqlx.DB, key string) (*model, error) {
78-
var res model
79-
query := `SELECT id, key, location, created_at, last_updated_at FROM ` + tableName + `
80-
WHERE key = $1
82+
func dbExtendExpiry(ctx context.Context, db *sqlx.DB, key, address string, expiry time.Time) error {
83+
query := `UPDATE ` + tableName + `
84+
SET expires_at = $1
85+
WHERE key = $2 AND address = $3 AND expires_at > NOW()
8186
`
8287

83-
err := db.GetContext(ctx, &res, query, key)
88+
res, err := db.ExecContext(ctx, query, expiry, key, address)
8489
if err != nil {
85-
return nil, pgutil.CheckNoRows(err, rendezvous.ErrNotFound)
90+
return err
8691
}
87-
return &res, nil
92+
rowsAffected, err := res.RowsAffected()
93+
if err != nil {
94+
return err
95+
} else if rowsAffected == 0 {
96+
return rendezvous.ErrNotFound
97+
}
98+
return nil
8899
}
89100

90-
func dbDelete(ctx context.Context, db *sqlx.DB, key string) error {
101+
func dbDelete(ctx context.Context, db *sqlx.DB, key, address string) error {
91102
query := `DELETE FROM ` + tableName + `
92-
WHERE key = $1
103+
WHERE key = $1 AND address = $2
93104
`
94105

95-
_, err := db.ExecContext(ctx, query, key)
106+
_, err := db.ExecContext(ctx, query, key, address)
96107
return err
97108
}
109+
110+
func dbGetByKey(ctx context.Context, db *sqlx.DB, key string) (*model, error) {
111+
var res model
112+
query := `SELECT id, key, address, created_at, expires_at FROM ` + tableName + `
113+
WHERE key = $1 AND expires_at > NOW()
114+
`
115+
116+
err := db.GetContext(ctx, &res, query, key)
117+
if err != nil {
118+
return nil, pgutil.CheckNoRows(err, rendezvous.ErrNotFound)
119+
}
120+
return &res, nil
121+
}

pkg/code/data/rendezvous/postgres/store.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package postgres
33
import (
44
"context"
55
"database/sql"
6+
"time"
67

78
"github.com/jmoiron/sqlx"
89

@@ -20,14 +21,14 @@ func New(db *sql.DB) rendezvous.Store {
2021
}
2122
}
2223

23-
// Save implements rendezvous.Store.Save
24-
func (s *store) Save(ctx context.Context, record *rendezvous.Record) error {
24+
// Put implements rendezvous.Store.Put
25+
func (s *store) Put(ctx context.Context, record *rendezvous.Record) error {
2526
obj, err := toModel(record)
2627
if err != nil {
2728
return err
2829
}
2930

30-
err = obj.dbSave(ctx, s.db)
31+
err = obj.dbPut(ctx, s.db)
3132
if err != nil {
3233
return err
3334
}
@@ -38,6 +39,16 @@ func (s *store) Save(ctx context.Context, record *rendezvous.Record) error {
3839
return nil
3940
}
4041

42+
// ExtendExpiry implements rendezvous.Store.ExtendExpiry
43+
func (s *store) ExtendExpiry(ctx context.Context, key, address string, expiry time.Time) error {
44+
return dbExtendExpiry(ctx, s.db, key, address, expiry)
45+
}
46+
47+
// Delete implements rendezvous.Store.Delete
48+
func (s *store) Delete(ctx context.Context, key, address string) error {
49+
return dbDelete(ctx, s.db, key, address)
50+
}
51+
4152
// Get implements rendezvous.Store.Get
4253
func (s *store) Get(ctx context.Context, key string) (*rendezvous.Record, error) {
4354
model, err := dbGetByKey(ctx, s.db, key)
@@ -47,8 +58,3 @@ func (s *store) Get(ctx context.Context, key string) (*rendezvous.Record, error)
4758

4859
return fromModel(model), nil
4960
}
50-
51-
// Delete implements rendezvous.Store.Delete
52-
func (s *store) Delete(ctx context.Context, key string) error {
53-
return dbDelete(ctx, s.db, key)
54-
}

pkg/code/data/rendezvous/postgres/store_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ const (
2323
id SERIAL NOT NULL PRIMARY KEY,
2424
2525
key TEXT NOT NULL,
26-
location TEXT NOT NULL,
26+
address TEXT NOT NULL,
2727
created_at TIMESTAMP WITH TIME ZONE,
28-
last_updated_at TIMESTAMP WITH TIME ZONE,
28+
expires_at TIMESTAMP WITH TIME ZONE,
2929
3030
CONSTRAINT codewallet__core_treasurypool__uniq__key UNIQUE (key)
3131
);

0 commit comments

Comments
 (0)