diff options
Diffstat (limited to 'src/state/models')
-rw-r--r-- | src/state/models/feed-view.ts | 1 | ||||
-rw-r--r-- | src/state/models/log.ts | 94 | ||||
-rw-r--r-- | src/state/models/me.ts | 15 | ||||
-rw-r--r-- | src/state/models/notifications-view.ts | 17 | ||||
-rw-r--r-- | src/state/models/profile-ui.ts | 16 | ||||
-rw-r--r-- | src/state/models/profile-view.ts | 1 | ||||
-rw-r--r-- | src/state/models/root-store.ts | 11 | ||||
-rw-r--r-- | src/state/models/session.ts | 26 | ||||
-rw-r--r-- | src/state/models/suggested-invites-view.ts | 14 |
9 files changed, 165 insertions, 30 deletions
diff --git a/src/state/models/feed-view.ts b/src/state/models/feed-view.ts index b5a3b29d7..c8827b1fb 100644 --- a/src/state/models/feed-view.ts +++ b/src/state/models/feed-view.ts @@ -405,7 +405,6 @@ export class FeedModel { cursor = this.feed[res.data.feed.length - 1] ? ts(this.feed[res.data.feed.length - 1]) : undefined - console.log(numToFetch, cursor, res.data.feed.length) } while (numToFetch > 0) this._xIdle() } catch (e: any) { diff --git a/src/state/models/log.ts b/src/state/models/log.ts new file mode 100644 index 000000000..42172a3b1 --- /dev/null +++ b/src/state/models/log.ts @@ -0,0 +1,94 @@ +import {makeAutoObservable} from 'mobx' +import {isObj, hasProp} from '../lib/type-guards' + +interface LogEntry { + id: string + type?: string + summary?: string + details?: string + ts?: number +} + +let _lastTs: string +let _lastId: string +function genId(): string { + let candidate = String(Date.now()) + if (_lastTs === candidate) { + const id = _lastId + 'x' + _lastId = id + return id + } + _lastTs = candidate + _lastId = candidate + return candidate +} + +export class LogModel { + entries: LogEntry[] = [] + + constructor() { + makeAutoObservable(this, {serialize: false, hydrate: false}) + } + + serialize(): unknown { + return { + entries: this.entries.slice(-100), + } + } + + hydrate(v: unknown) { + if (isObj(v)) { + if (hasProp(v, 'entries') && Array.isArray(v.entries)) { + this.entries = v.entries.filter( + e => isObj(e) && hasProp(e, 'id') && typeof e.id === 'string', + ) + } + } + } + + private add(entry: LogEntry) { + this.entries.push(entry) + } + + debug(summary: string, details?: any) { + if (details && typeof details !== 'string') { + details = JSON.stringify(details, null, 2) + } + console.debug(summary, details || '') + this.add({ + id: genId(), + type: 'debug', + summary, + details, + ts: Date.now(), + }) + } + + warn(summary: string, details?: any) { + if (details && typeof details !== 'string') { + details = JSON.stringify(details, null, 2) + } + console.warn(summary, details || '') + this.add({ + id: genId(), + type: 'warn', + summary, + details, + ts: Date.now(), + }) + } + + error(summary: string, details?: any) { + if (details && typeof details !== 'string') { + details = JSON.stringify(details, null, 2) + } + console.error(summary, details || '') + this.add({ + id: genId(), + type: 'error', + summary, + details, + ts: Date.now(), + }) + } +} diff --git a/src/state/models/me.ts b/src/state/models/me.ts index 9591acb80..ae1e6aed2 100644 --- a/src/state/models/me.ts +++ b/src/state/models/me.ts @@ -104,13 +104,22 @@ export class MeModel { }) await Promise.all([ this.memberships?.setup().catch(e => { - console.error('Failed to setup memberships model', e) + this.rootStore.log.error( + 'Failed to setup memberships model', + e.toString(), + ) }), this.mainFeed.setup().catch(e => { - console.error('Failed to setup main feed model', e) + this.rootStore.log.error( + 'Failed to setup main feed model', + e.toString(), + ) }), this.notifications.setup().catch(e => { - console.error('Failed to setup notifications model', e) + this.rootStore.log.error( + 'Failed to setup notifications model', + e.toString(), + ) }), ]) } else { diff --git a/src/state/models/notifications-view.ts b/src/state/models/notifications-view.ts index c1ee78d41..38a8ca133 100644 --- a/src/state/models/notifications-view.ts +++ b/src/state/models/notifications-view.ts @@ -149,7 +149,10 @@ export class NotificationsViewItemModel implements GroupedNotification { depth: 0, }) await this.additionalPost.setup().catch(e => { - console.error('Failed to load post needed by notification', e) + this.rootStore.log.error( + 'Failed to load post needed by notification', + e.toString(), + ) }) } } @@ -262,8 +265,11 @@ export class NotificationsViewModel { seenAt: new Date().toISOString(), }) this.rootStore.me.clearNotificationCount() - } catch (e) { - console.log('Failed to update notifications read state', e) + } catch (e: any) { + this.rootStore.log.warn( + 'Failed to update notifications read state', + e.toString(), + ) } } @@ -350,7 +356,6 @@ export class NotificationsViewModel { this._updateAll(res) numToFetch -= res.data.notifications.length cursor = this.notifications[res.data.notifications.length - 1].indexedAt - console.log(numToFetch, cursor, res.data.notifications.length) } while (numToFetch > 0) this._xIdle() } catch (e: any) { @@ -379,9 +384,9 @@ export class NotificationsViewModel { itemModels.push(itemModel) } await Promise.all(promises).catch(e => { - console.error( + this.rootStore.log.error( 'Uncaught failure during notifications-view _appendAll()', - e, + e.toString(), ) }) runInAction(() => { diff --git a/src/state/models/profile-ui.ts b/src/state/models/profile-ui.ts index d0eb1f858..081160e65 100644 --- a/src/state/models/profile-ui.ts +++ b/src/state/models/profile-ui.ts @@ -114,20 +114,28 @@ export class ProfileUiModel { await Promise.all([ this.profile .setup() - .catch(err => console.error('Failed to fetch profile', err)), + .catch(err => + this.rootStore.log.error('Failed to fetch profile', err.toString()), + ), this.feed .setup() - .catch(err => console.error('Failed to fetch feed', err)), + .catch(err => + this.rootStore.log.error('Failed to fetch feed', err.toString()), + ), ]) if (this.isUser) { await this.memberships .setup() - .catch(err => console.error('Failed to fetch members', err)) + .catch(err => + this.rootStore.log.error('Failed to fetch members', err.toString()), + ) } if (this.isScene) { await this.members .setup() - .catch(err => console.error('Failed to fetch members', err)) + .catch(err => + this.rootStore.log.error('Failed to fetch members', err.toString()), + ) } } diff --git a/src/state/models/profile-view.ts b/src/state/models/profile-view.ts index 2a69a1345..1c825a482 100644 --- a/src/state/models/profile-view.ts +++ b/src/state/models/profile-view.ts @@ -203,7 +203,6 @@ export class ProfileViewModel { } private _replaceAll(res: GetProfile.Response) { - console.log(res.data) this.did = res.data.did this.handle = res.data.handle Object.assign(this.declaration, res.data.declaration) diff --git a/src/state/models/root-store.ts b/src/state/models/root-store.ts index 54578b4a5..0166b67e6 100644 --- a/src/state/models/root-store.ts +++ b/src/state/models/root-store.ts @@ -6,6 +6,7 @@ import {makeAutoObservable} from 'mobx' import {sessionClient as AtpApi, SessionServiceClient} from '@atproto/api' import {createContext, useContext} from 'react' import {isObj, hasProp} from '../lib/type-guards' +import {LogModel} from './log' import {SessionModel} from './session' import {NavigationModel} from './navigation' import {ShellUiModel} from './shell-ui' @@ -16,6 +17,7 @@ import {OnboardModel} from './onboard' import {isNetworkError} from '../../lib/errors' export class RootStoreModel { + log = new LogModel() session = new SessionModel(this) nav = new NavigationModel() shell = new ShellUiModel() @@ -53,16 +55,17 @@ export class RootStoreModel { await this.session.connect() } await this.me.fetchStateUpdate() - } catch (e: unknown) { + } catch (e: any) { if (isNetworkError(e)) { this.session.setOnline(false) // connection lost } - console.error('Failed to fetch latest state', e) + this.log.error('Failed to fetch latest state', e.toString()) } } serialize(): unknown { return { + log: this.log.serialize(), session: this.session.serialize(), me: this.me.serialize(), nav: this.nav.serialize(), @@ -73,8 +76,8 @@ export class RootStoreModel { hydrate(v: unknown) { if (isObj(v)) { - if (hasProp(v, 'session')) { - this.session.hydrate(v.session) + if (hasProp(v, 'log')) { + this.log.hydrate(v.log) } if (hasProp(v, 'me')) { this.me.hydrate(v.me) diff --git a/src/state/models/session.ts b/src/state/models/session.ts index febffcec3..3efb5d2a6 100644 --- a/src/state/models/session.ts +++ b/src/state/models/session.ts @@ -121,11 +121,11 @@ export class SessionModel { try { const serviceUri = new URL(this.data.service) this.rootStore.api.xrpc.uri = serviceUri - } catch (e) { - console.error( + } catch (e: any) { + this.rootStore.log.error( `Invalid service URL: ${this.data.service}. Resetting session.`, + e.toString(), ) - console.error(e) this.clear() return false } @@ -160,7 +160,10 @@ export class SessionModel { this.rootStore.me.clear() } this.rootStore.me.load().catch(e => { - console.error('Failed to fetch local user information', e) + this.rootStore.log.error( + 'Failed to fetch local user information', + e.toString(), + ) }) return // success } @@ -204,7 +207,10 @@ export class SessionModel { this.configureApi() this.setOnline(true, false) this.rootStore.me.load().catch(e => { - console.error('Failed to fetch local user information', e) + this.rootStore.log.error( + 'Failed to fetch local user information', + e.toString(), + ) }) } } @@ -240,7 +246,10 @@ export class SessionModel { this.rootStore.onboard.start() this.configureApi() this.rootStore.me.load().catch(e => { - console.error('Failed to fetch local user information', e) + this.rootStore.log.error( + 'Failed to fetch local user information', + e.toString(), + ) }) } } @@ -248,7 +257,10 @@ export class SessionModel { async logout() { if (this.hasSession) { this.rootStore.api.com.atproto.session.delete().catch((e: any) => { - console.error('(Minor issue) Failed to delete session on the server', e) + this.rootStore.log.warn( + '(Minor issue) Failed to delete session on the server', + e, + ) }) } this.rootStore.clearAll() diff --git a/src/state/models/suggested-invites-view.ts b/src/state/models/suggested-invites-view.ts index 33ca7396e..eb0665bca 100644 --- a/src/state/models/suggested-invites-view.ts +++ b/src/state/models/suggested-invites-view.ts @@ -98,8 +98,11 @@ export class SuggestedInvitesView { try { // TODO need to fetch all! await this.sceneAssertionsView.setup() - } catch (e) { - console.error(e) + } catch (e: any) { + this.rootStore.log.error( + 'Failed to fetch current scene members in suggested invites', + e.toString(), + ) this._xIdle( 'Failed to fetch the current scene members. Check your internet connection and try again.', ) @@ -107,8 +110,11 @@ export class SuggestedInvitesView { } try { await this.myFollowsView.setup() - } catch (e) { - console.error(e) + } catch (e: any) { + this.rootStore.log.error( + 'Failed to fetch current followers in suggested invites', + e.toString(), + ) this._xIdle( 'Failed to fetch the your current followers. Check your internet connection and try again.', ) |