marco/app/services/storage.js
2026-01-17 18:17:26 +07:00

101 lines
3.4 KiB
JavaScript

import Service from '@ember/service';
import RemoteStorage from 'remotestoragejs';
import Places from '@remotestorage/module-places';
import Widget from 'remotestorage-widget';
import { tracked } from '@glimmer/tracking';
export default class StorageService extends Service {
rs;
@tracked savedPlaces = [];
@tracked version = 0; // Shared version tracker for bookmarks
constructor() {
super(...arguments);
console.log('ohai');
this.rs = new RemoteStorage({
modules: [Places],
});
this.rs.access.claim('places', 'rw');
// Caching strategy:
// With the new nested structure, enabling caching on root '/' might try to sync everything.
// For now, let's keep it, but we might need to be more selective later if data grows huge.
// Note: The path structure changed from /places/ to just root access in the module?
// In places.ts: getPath returns "ab/cd/id".
// RemoteStorage modules usually implicitly use a base scope based on module name if not defined differently?
// Wait, the module defines `privateClient`.
// When we do `privateClient.storeObject`, it stores it under the module's scope.
// If module name is 'places', then it's stored under /places/.
// So getPath "ab/cd/id" becomes "/places/ab/cd/id".
// So enabling caching on '/places/' is correct.
// However, per instructions, we should set maxAge to false for listings in the module,
// which we did.
// We also need to be careful about what we cache here.
this.rs.caching.enable('/places/');
window.remoteStorage = this.rs;
// const widget = new Widget(this.rs);
// widget.attach();
this.rs.on('ready', () => {
this.loadAllPlaces();
});
this.rs.scope('/places/').on('change', () => {
this.loadAllPlaces();
});
}
get places() {
return this.rs.places;
}
notifyChange() {
this.version++;
this.loadAllPlaces();
}
async loadAllPlaces(prefixes = null) {
try {
// If prefixes is null, it loads everything (recursive scan).
// If prefixes is an array ['w1q7'], it loads just that sector.
const places = await this.rs.places.getPlaces(prefixes);
if (places && Array.isArray(places)) {
if (prefixes) {
// If partial load, we might want to merge instead of replace?
// For now, let's keep the simple behavior: replacing the tracked array triggers updates.
// However, replacing 'all saved places' with 'just these visible places'
// might hide other bookmarks from the list.
// Strategy: maintain a Map of loaded places to avoid duplicates/overwrites?
// Or just append unique ones?
const currentIds = new Set(this.savedPlaces.map((p) => p.id));
const newPlaces = places.filter((p) => !currentIds.has(p.id));
this.savedPlaces = [...this.savedPlaces, ...newPlaces];
} else {
// Full reload
this.savedPlaces = places;
}
} else {
if (!prefixes) this.savedPlaces = [];
}
console.log('Loaded saved places:', this.savedPlaces.length);
} catch (e) {
console.error('Failed to load places:', e);
}
}
findPlaceById(id) {
// Search by internal ID first
let place = this.savedPlaces.find((p) => p.id === id);
if (place) return place;
// Then search by OSM ID
place = this.savedPlaces.find((p) => p.osmId === id);
return place;
}
}