Fix Circle Service with new database code

This commit is contained in:
SondreB 2023-01-29 20:04:04 +01:00
parent 54074601f0
commit 391a2a71e0
No known key found for this signature in database
GPG Key ID: D6CC44C75005FDBF
11 changed files with 139 additions and 97 deletions

View File

@ -185,6 +185,7 @@ export class AppComponent {
/** Run initialize whenever user has been authenticated. */
async initialize() {
debugger;
// await this.storage.open();
// await this.storage.initialize();
await this.db.initialize('blockcore-' + this.appState.getPublicKey());
@ -253,6 +254,8 @@ export class AppComponent {
},
});
debugger;
// Create the listeners (filters) for relays:
// TODO: There is limit on maximum following, we need a strategy to handle that.
// potentially subscribing and unsubscribing on intervals with a .since field between each interval.
@ -263,7 +266,11 @@ export class AppComponent {
console.log('PUB KEYS:', pubKeys);
this.relayService.queueSubscription([{ authors: pubKeys }]);
// Subscribe to new events but don't get any history (limit: 0).
console.log('queueSubscription:', { authors: pubKeys, since: this.db.state.since });
this.relayService.queueSubscription([{ authors: pubKeys, since: this.db.state.since }]);
// this.relayService.

View File

@ -2,53 +2,44 @@
<div class="feed-page">
<!-- <p>Circles is how you organize people you follow. Different circles can have different rules applied and circles is an important way to make the experience more enjoyable.</p> -->
<div *ngIf="items$ | withStatus | async as items">
<ng-template [ngIf]="items.value">
<mat-card class="circle-container" *ngFor="let circle of items.value">
<div class="circle-item"><mat-icon matListItemIcon [style.color]="circle.color">trip_origin</mat-icon></div>
<div class="circle-item">
{{ circle.name }}<br />
<span class="dimmed"
><span>Count: {{ countMembers(circle) }}</span></span
><br />
<span class="dimmed"><span *ngIf="circle.public">Public</span> <span *ngIf="!circle.public">Private</span> - {{ circle.style | circlestyle }} - Created: {{ circle.created | ago }}</span>
</div>
<div class="circle-item">
<button class="circle-button" mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon class="circle-button-icon">more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item [matMenuTriggerFor]="copyMenu">
<mat-icon>copy_all</mat-icon>
<span>Copy</span>
</button>
<button *ngIf="circle.id" mat-menu-item (click)="deleteCircle(circle.id)">
<mat-icon>delete</mat-icon>
<span>Delete Circle</span>
</button>
</mat-menu>
<mat-menu #copyMenu="matMenu">
<button mat-menu-item (click)="copyPubKeys(circle)">
<mat-icon>content_copy</mat-icon>
<span>Public Keys (npub)</span>
</button>
<button mat-menu-item (click)="copyPubKeysHex(circle)">
<mat-icon>content_copy</mat-icon>
<span>Public Keys (hex)</span>
</button>
</mat-menu>
</div>
</mat-card>
</ng-template>
<ng-template [ngIf]="items.loading"><mat-spinner class="loading"></mat-spinner></ng-template>
<ng-template [ngIf]="items.error">Error {{ items.error }}</ng-template>
</div>
<mat-card class="circle-container" *ngFor="let circle of circleService.circles">
<div class="circle-item"><mat-icon matListItemIcon [style.color]="circle.color">trip_origin</mat-icon></div>
<div class="circle-item">
{{ circle.name }}<br />
<span class="dimmed"><span>Count: {{ countMembers(circle) }}</span></span
><br />
<span class="dimmed"><span *ngIf="circle.public">Public</span> <span *ngIf="!circle.public">Private</span> - {{ circle.style | circlestyle }} - Created: {{ circle.created | ago }}</span>
</div>
<div class="circle-item">
<button class="circle-button" mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon class="circle-button-icon">more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item [matMenuTriggerFor]="copyMenu">
<mat-icon>copy_all</mat-icon>
<span>Copy</span>
</button>
<button *ngIf="circle.id" mat-menu-item (click)="deleteCircle(circle.id)">
<mat-icon>delete</mat-icon>
<span>Delete Circle</span>
</button>
</mat-menu>
<mat-menu #copyMenu="matMenu">
<button mat-menu-item (click)="copyPubKeys(circle)">
<mat-icon>content_copy</mat-icon>
<span>Public Keys (npub)</span>
</button>
<button mat-menu-item (click)="copyPubKeysHex(circle)">
<mat-icon>content_copy</mat-icon>
<span>Public Keys (hex)</span>
</button>
</mat-menu>
</div>
</mat-card>
<!-- <mat-card class="circle-container" *ngFor="let circle of circles">
<div class="circle-item"><mat-icon matListItemIcon [style.color]="circle.color">trip_origin</mat-icon></div>
<div class="circle-item">

View File

@ -26,12 +26,12 @@ export class CirclesComponent {
following: NostrProfileDocument[] = [];
searchTerm: any;
items: Circle[] = [];
items$ = this.circleService.items$.pipe(
tap((items) => {
this.items = items;
})
);
// items: Circle[] = [];
// items$ = this.circleService.items$.pipe(
// tap((items) => {
// this.items = items;
// })
// );
constructor(
public appState: ApplicationState,
@ -104,13 +104,13 @@ export class CirclesComponent {
}
private getPublicPublicKeys() {
console.log(this.items);
// console.log(this.items);
console.log(this.following);
const items: string[] = [];
for (let i = 0; i < this.items.length; i++) {
const circle = this.items[i];
for (let i = 0; i < this.circleService.circles.length; i++) {
const circle = this.circleService.circles[i];
if (circle.public) {
const profiles = this.getFollowingInCircle(circle.id);
@ -242,6 +242,6 @@ export class CirclesComponent {
},
];
this.subscriptions.push(this.profileService.items$.subscribe((profiles) => (this.following = profiles)) as Subscription);
// this.subscriptions.push(this.profileService.items$.subscribe((profiles) => (this.following = profiles)) as Subscription);
}
}

View File

@ -18,7 +18,7 @@ import { StorageService } from '../services/storage';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { dexieToRx } from '../shared/utilities';
import { liveQuery } from 'dexie';
interface DefaultProfile {
pubkey: string;
pubkeynpub: string;
@ -182,6 +182,8 @@ export class HomeComponent {
// Do what should be done next...
});
await this.db.storage.delete();
location.reload();
}

View File

@ -1,7 +1,6 @@
import { Injectable } from '@angular/core';
import { Circle } from './interfaces';
import { BehaviorSubject, from, Observable } from 'rxjs';
import { liveQuery } from 'dexie';
import { StorageService } from './storage';
import { CacheService } from './cache';
import { Utilities } from './utilities';
@ -11,32 +10,30 @@ import { dexieToRx } from '../shared/utilities';
providedIn: 'root',
})
export class CircleService {
static DEFAULT: Circle[] = [{ id: 0, name: 'Following', color: '#e91e63', style: 1, public: true },
{id: 1, name: "Text", color: '#7cb342', style: 2, public: true},
{id: 2, name: "Photo", color: '#ffb300', style: 3, public: true},
{id: 3, name: "Film", color: '#26c6da', style: 4, public: true},
{id: 4, name: "Music", color: '#ba9eea', style: 5, public: true},
{id: 5, name: "Podcast", color: '#ff8a65', style: 6, public: true}];
private get table() {
return this.db.circles;
}
static DEFAULT: Circle[] = [
{ id: 0, name: 'Following', color: '#e91e63', style: 1, public: true },
{ id: 1, name: 'Text', color: '#7cb342', style: 2, public: true },
{ id: 2, name: 'Photo', color: '#ffb300', style: 3, public: true },
{ id: 3, name: 'Film', color: '#26c6da', style: 4, public: true },
{ id: 4, name: 'Music', color: '#ba9eea', style: 5, public: true },
{ id: 5, name: 'Podcast', color: '#ff8a65', style: 6, public: true },
];
circles: Circle[] = [];
cache = new CacheService();
items$ = dexieToRx(liveQuery(() => this.items()));
// items$ = dexieToRx(liveQuery(() => this.items()));
async items() {
return await this.table.toArray();
}
// async items() {
// return await this.table.toArray();
// }
constructor(private db: StorageService, private utilities: Utilities) {}
/** Important to call to ensure we have the default circle added */
async initialize() {
const defaultCircle = await this.table.get(0);
const defaultCircle = await this.db.storage.getCircle(0);
if (!defaultCircle) {
for (let index = 0; index < CircleService.DEFAULT.length; index++) {
@ -45,10 +42,7 @@ export class CircleService {
}
}
// Cache the circle so we can lookup quickly.
this.items$.subscribe((circles) => {
this.circles = circles;
});
this.circles = await this.db.storage.getCircles();
}
getSync(id?: number) {
@ -68,7 +62,7 @@ export class CircleService {
if (this.circles.length > 0) {
return this.circles.find((c) => c.id == id);
} else {
return await this.table.get(id);
return await this.db.storage.getCircle(id);
}
}
@ -80,15 +74,10 @@ export class CircleService {
}
document.modified = now;
await this.table.put(document);
await this.db.storage.putCircle(document);
}
async delete(id: number) {
await this.table.delete(id);
}
/** Wipes all circles. */
async wipe() {
this.table.clear();
await this.db.storage.deleteCircle(id);
}
}

View File

@ -74,6 +74,12 @@ export interface NostrRelaySubscription {
filters: Filter[];
}
export interface StateDocument {
id: number;
since: number;
modified?: number;
}
export interface NostrRelayDocument {
url: string;
// read: boolean;

View File

@ -206,8 +206,6 @@ export class RelayService {
const index = this.workers.findIndex((v) => v.url == url);
const worker = this.workers[index];
debugger;
for (let index = 0; index < this.subs2.length; index++) {
const sub = this.subs2[index];
worker.subscribe(sub.filters, sub.id);

View File

@ -2,8 +2,9 @@ import { Injectable } from '@angular/core';
import Dexie, { Table } from 'dexie';
import { ApplicationState } from './applicationstate';
import { DatabaseService } from './database';
import { Circle, NostrEventDocument, NostrNoteDocument, NostrProfileDocument, NostrRelayDocument } from './interfaces';
import { Circle, NostrEventDocument, NostrNoteDocument, NostrProfileDocument, NostrRelayDocument, StateDocument } from './interfaces';
import { Storage } from '../types/storage';
import * as moment from 'moment';
@Injectable({
providedIn: 'root',
@ -34,15 +35,42 @@ export class StorageService {
}
db!: DatabaseService;
state!: StateDocument;
async initialize(databaseName: string) {
// Open the new storage database.
this.storage = new Storage('blockcore-notes-' + this.appState.getPublicKey(), 1);
await this.storage.open();
let state = await this.storage.getState();
if (!state) {
// The initial since we will use is two days past.
const timeAgo = moment().subtract(2, 'days').unix();
state = {
id: 1,
since: timeAgo,
};
}
this.state = state;
// Update the state on interval.
setTimeout(async () => {
console.log('Persisting state...');
// The since will always be set slightly back in time to counteract difference in clocks
// for different event creators on the nostr network.
const timeAgo = moment().subtract(10, 'minutes').unix();
this.state.since = timeAgo;
await this.storage.putState(this.state);
}, 60 * 1000);
// TODO: Remove, old code.
this.db = new DatabaseService(databaseName);
return this.db.open();
// this.db = new DatabaseService(databaseName);
// return this.db.open();
}
close() {

View File

@ -68,7 +68,7 @@
</mat-menu>
<mat-menu #categories="matMenu">
<button *ngFor="let circle of circleService.items$ | async" mat-menu-item (click)="follow(circle.id)">
<button *ngFor="let circle of circleService.circles" mat-menu-item (click)="follow(circle.id)">
<mat-icon [style.color]="circle.color">trip_origin</mat-icon>
<span>{{ circle.name }}</span>
</button>

View File

@ -1,5 +1,5 @@
import { openDB, deleteDB, wrap, unwrap, IDBPDatabase, DBSchema } from 'idb';
import { Circle, NostrEventDocument, NostrNoteDocument, NostrProfileDocument, NostrRelayDocument } from '../services/interfaces';
import { Circle, NostrEventDocument, NostrNoteDocument, NostrProfileDocument, NostrRelayDocument, StateDocument } from '../services/interfaces';
/** Make sure you read and learn: https://github.com/jakearchibald/idb */
@ -8,6 +8,10 @@ export function now() {
}
interface NotesDB extends DBSchema {
state: {
value: StateDocument;
key: number;
};
relays: {
value: NostrRelayDocument;
key: string;
@ -35,7 +39,7 @@ interface NotesDB extends DBSchema {
export class Storage {
public db!: IDBPDatabase<NotesDB>;
constructor(private name: string, private version: number) { }
constructor(private name: string, private version: number) {}
async open() {
this.db = await openDB<NotesDB>(this.name, this.version, {
@ -43,6 +47,7 @@ export class Storage {
db.createObjectStore('relays', { keyPath: 'url' });
db.createObjectStore('notes', { keyPath: 'id' });
db.createObjectStore('circles', { keyPath: 'id' });
db.createObjectStore('state', { keyPath: 'id' });
const eventsStore = db.createObjectStore('events', { keyPath: 'id' });
eventsStore.createIndex('pubkey', 'pubkey');
@ -67,10 +72,24 @@ export class Storage {
this.db.close();
}
async getState() {
return this.db.get('state', 1);
}
async putState(value: StateDocument) {
value.id = 1;
value.modified = now();
return this.db.put('state', value);
}
async getCircle(key: number) {
return this.db.get('circles', key);
}
async getCircles() {
return this.db.getAll('circles');
}
async putCircle(value: Circle) {
value.modified = now();
return this.db.put('circles', value);
@ -118,6 +137,10 @@ export class Storage {
return this.db.put('relays', value);
}
async deleteCircle(key: number) {
return this.db.delete('circles', key);
}
async deleteRelay(key: string) {
return this.db.delete('relays', key);
}

View File

@ -78,7 +78,6 @@ addEventListener('message', async (ev: MessageEvent) => {
await relayWorker.publish(request.data);
break;
case 'subscribe':
debugger;
await relayWorker.subscribe(request.data.filters, request.data.id);
break;
case 'unsubscribe':
@ -136,7 +135,6 @@ export class RelayWorker {
relay.on('disconnect', () => {
console.log(`DISCONNECTED! ${relay?.url}`);
debugger;
this.subscriptions = [];
postMessage({ type: 'status', data: 0, url: relay.url } as RelayResponse);
});