You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
4.5 KiB
181 lines
4.5 KiB
package neo4j |
|
|
|
import ( |
|
"encoding/json" |
|
"fmt" |
|
"time" |
|
|
|
"next.orly.dev/pkg/database" |
|
"git.mleku.dev/mleku/nostr/encoders/hex" |
|
) |
|
|
|
// Subscription and payment methods |
|
// Simplified implementation using marker-based storage via Badger |
|
// For production graph-based storage, these could use Neo4j nodes with relationships |
|
|
|
// GetSubscription retrieves subscription information for a pubkey |
|
func (n *N) GetSubscription(pubkey []byte) (*database.Subscription, error) { |
|
key := "sub_" + hex.Enc(pubkey) |
|
data, err := n.GetMarker(key) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
var sub database.Subscription |
|
if err := json.Unmarshal(data, &sub); err != nil { |
|
return nil, fmt.Errorf("failed to unmarshal subscription: %w", err) |
|
} |
|
|
|
return &sub, nil |
|
} |
|
|
|
// IsSubscriptionActive checks if a pubkey has an active subscription |
|
func (n *N) IsSubscriptionActive(pubkey []byte) (bool, error) { |
|
sub, err := n.GetSubscription(pubkey) |
|
if err != nil { |
|
return false, nil // No subscription = not active |
|
} |
|
|
|
return sub.PaidUntil.After(time.Now()), nil |
|
} |
|
|
|
// ExtendSubscription extends a subscription by the specified number of days |
|
func (n *N) ExtendSubscription(pubkey []byte, days int) error { |
|
key := "sub_" + hex.Enc(pubkey) |
|
|
|
// Get existing subscription or create new |
|
var sub database.Subscription |
|
data, err := n.GetMarker(key) |
|
if err == nil { |
|
if err := json.Unmarshal(data, &sub); err != nil { |
|
return fmt.Errorf("failed to unmarshal subscription: %w", err) |
|
} |
|
} else { |
|
// New subscription - set trial period |
|
sub.TrialEnd = time.Now() |
|
sub.PaidUntil = time.Now() |
|
} |
|
|
|
// Extend expiration |
|
if sub.PaidUntil.Before(time.Now()) { |
|
sub.PaidUntil = time.Now() |
|
} |
|
sub.PaidUntil = sub.PaidUntil.Add(time.Duration(days) * 24 * time.Hour) |
|
|
|
// Save |
|
data, err = json.Marshal(sub) |
|
if err != nil { |
|
return fmt.Errorf("failed to marshal subscription: %w", err) |
|
} |
|
|
|
return n.SetMarker(key, data) |
|
} |
|
|
|
// RecordPayment records a payment for subscription extension |
|
func (n *N) RecordPayment( |
|
pubkey []byte, amount int64, invoice, preimage string, |
|
) error { |
|
// Store payment in payments list |
|
key := "payments_" + hex.Enc(pubkey) |
|
|
|
var payments []database.Payment |
|
data, err := n.GetMarker(key) |
|
if err == nil { |
|
if err := json.Unmarshal(data, &payments); err != nil { |
|
return fmt.Errorf("failed to unmarshal payments: %w", err) |
|
} |
|
} |
|
|
|
payment := database.Payment{ |
|
Amount: amount, |
|
Timestamp: time.Now(), |
|
Invoice: invoice, |
|
Preimage: preimage, |
|
} |
|
|
|
payments = append(payments, payment) |
|
|
|
data, err = json.Marshal(payments) |
|
if err != nil { |
|
return fmt.Errorf("failed to marshal payments: %w", err) |
|
} |
|
|
|
return n.SetMarker(key, data) |
|
} |
|
|
|
// GetPaymentHistory retrieves payment history for a pubkey |
|
func (n *N) GetPaymentHistory(pubkey []byte) ([]database.Payment, error) { |
|
key := "payments_" + hex.Enc(pubkey) |
|
|
|
data, err := n.GetMarker(key) |
|
if err != nil { |
|
return nil, nil // No payments = empty list |
|
} |
|
|
|
var payments []database.Payment |
|
if err := json.Unmarshal(data, &payments); err != nil { |
|
return nil, fmt.Errorf("failed to unmarshal payments: %w", err) |
|
} |
|
|
|
return payments, nil |
|
} |
|
|
|
// ExtendBlossomSubscription extends a Blossom storage subscription |
|
func (n *N) ExtendBlossomSubscription( |
|
pubkey []byte, tier string, storageMB int64, daysExtended int, |
|
) error { |
|
key := "blossom_" + hex.Enc(pubkey) |
|
|
|
// Simple implementation - just store tier and expiry |
|
data := map[string]interface{}{ |
|
"tier": tier, |
|
"storageMB": storageMB, |
|
"extended": daysExtended, |
|
"updated": time.Now(), |
|
} |
|
|
|
jsonData, err := json.Marshal(data) |
|
if err != nil { |
|
return fmt.Errorf("failed to marshal blossom subscription: %w", err) |
|
} |
|
|
|
return n.SetMarker(key, jsonData) |
|
} |
|
|
|
// GetBlossomStorageQuota retrieves the storage quota for a pubkey |
|
func (n *N) GetBlossomStorageQuota(pubkey []byte) (quotaMB int64, err error) { |
|
key := "blossom_" + hex.Enc(pubkey) |
|
|
|
data, err := n.GetMarker(key) |
|
if err != nil { |
|
return 0, nil // No subscription = 0 quota |
|
} |
|
|
|
var subData map[string]interface{} |
|
if err := json.Unmarshal(data, &subData); err != nil { |
|
return 0, fmt.Errorf("failed to unmarshal blossom data: %w", err) |
|
} |
|
|
|
if storageMB, ok := subData["storageMB"].(float64); ok { |
|
return int64(storageMB), nil |
|
} |
|
|
|
return 0, nil |
|
} |
|
|
|
// IsFirstTimeUser checks if this is the first time a user is accessing the relay |
|
func (n *N) IsFirstTimeUser(pubkey []byte) (bool, error) { |
|
key := "first_seen_" + hex.Enc(pubkey) |
|
|
|
// If marker exists, not first time |
|
if n.HasMarker(key) { |
|
return false, nil |
|
} |
|
|
|
// Mark as seen |
|
if err := n.SetMarker(key, []byte{1}); err != nil { |
|
return true, err |
|
} |
|
|
|
return true, nil |
|
}
|
|
|