Skip to content
This repository has been archived by the owner on Oct 25, 2023. It is now read-only.

local storage: fix node & edge ownership #422

Merged
merged 10 commits into from
Jan 31, 2023
20 changes: 17 additions & 3 deletions archaeologist/src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
makeAlwaysThrowingStorageApi,
makeDatacenterStorageApi,
processMsgFromMsgProxyStorageApi,
UserAccount,
} from 'smuggler-api'

import { makeBrowserExtStorageApi } from './storage_api_browser_ext'
Expand Down Expand Up @@ -824,17 +825,30 @@ async function initMazedPartsOfTab(
}
}

function makeStorageApi(appSettings: AppSettings): StorageApi {
function makeStorageApi(
appSettings: AppSettings,
account: UserAccount
): StorageApi {
switch (appSettings.storageType) {
case 'datacenter':
return makeDatacenterStorageApi()
case 'browser_ext':
return makeBrowserExtStorageApi(browser.storage.local)
return makeBrowserExtStorageApi(browser.storage.local, account)
}
}

async function initBackground() {
storage = makeStorageApi(await getAppSettings(browser.storage.local))
auth.observe({
onLogin: async (account: UserAccount) => {
storage = makeStorageApi(
await getAppSettings(browser.storage.local),
account
)
},
onLogout: () => {
storage = makeAlwaysThrowingStorageApi()
},
})

browser.runtime.onMessage.addListener(
async (
Expand Down
66 changes: 39 additions & 27 deletions archaeologist/src/background/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
UserAccount,
} from 'smuggler-api'
import { Knocker, authCookie } from 'smuggler-api'
import { log, isAbortError } from 'armoury'
import { log, isAbortError, errorise } from 'armoury'
import { v4 as uuidv4 } from 'uuid'

// Periodically renew auth token using Knocker
const _authKnocker = new Knocker(
Expand Down Expand Up @@ -60,10 +61,35 @@ const _authKnocker = new Knocker(
)

let _account: AccountInterface = new AnonymousAccount()
// External listener for login events
let _onLoginListener: ((account: UserAccount) => void) | null = null
// External listener for logout events
let _onLogoutListener: (() => void) | null = null
const _listeners: Map<
string /*listener ID*/,
{
// External listener for login events
onLogin: (account: UserAccount) => void
// External listener for logout events
onLogout: () => void
}
> = new Map()

function _onLogin(account: UserAccount) {
for (const { onLogin } of _listeners.values()) {
try {
onLogin(account)
} catch (reason) {
log.error(`onLogin listener failed: ${errorise(reason).message}`)
}
}
}

function _onLogout() {
for (const { onLogout } of _listeners.values()) {
try {
onLogout()
} catch (reason) {
log.error(`onLogin listener failed: ${errorise(reason).message}`)
}
}
}

function isAuthenticated(account: AccountInterface): account is UserAccount {
return account.isAuthenticated()
Expand Down Expand Up @@ -91,9 +117,7 @@ async function _loginHandler() {
if (!_authKnocker.isActive()) {
await _authKnocker.start({ onKnockFailure })
}
if (_onLoginListener) {
_onLoginListener(_account)
}
_onLogin(_account)
}
await badge.setActive(_account.isAuthenticated())
}
Expand All @@ -103,9 +127,7 @@ async function _logoutHandler() {
_account = new AnonymousAccount()
await _authKnocker.abort()
await badge.setActive(false)
if (_onLogoutListener) {
_onLogoutListener()
}
_onLogout()
}

// Actions to do on authorisation token renewal failure (knock of Knocker)
Expand Down Expand Up @@ -155,23 +177,16 @@ export function observe({
onLogin: (account: UserAccount) => void
onLogout: () => void
}): () => void {
if (_onLoginListener != null || _onLogoutListener != null) {
throw new Error(
'Background authentication is already being observed, ' +
'to observe from multiple places the functionality has to be extended'
)
}
_onLoginListener = onLogin
_onLogoutListener = onLogout
const listenerId = uuidv4()
_listeners.set(listenerId, { onLogin, onLogout })

const unregister = () => {
_onLoginListener = null
_onLogoutListener = null
_listeners.delete(listenerId)
}

try {
if (isAuthenticated(_account)) {
_onLoginListener(_account)
onLogin(_account)
}
} catch (e) {
unregister()
Expand Down Expand Up @@ -202,12 +217,9 @@ export async function register() {
browser.cookies.onChanged.removeListener(onChangedCookiesListener)
await _logoutHandler()
try {
if (_onLogoutListener) {
_onLogoutListener()
}
_onLogout()
} finally {
_onLoginListener = null
_onLogoutListener = null
_listeners.clear()
}
}
}
28 changes: 14 additions & 14 deletions archaeologist/src/storage_api_browser_ext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import type {
ExternalIngestionAdvanceArgs,
ExternalIngestionGetArgs,
NodeGetAllNidsArgs,
UserAccount,
} from 'smuggler-api'
import {
INodeIterator,
Expand Down Expand Up @@ -278,12 +279,12 @@ function generateEid(): Eid {

async function createNode(
store: YekLavStore,
args: NodeCreateArgs
args: NodeCreateArgs,
account: UserAccount
): Promise<NewNodeResponse> {
// TODO[snikitin@outlook.com] Below keys must become functional somehow.
// const _created_via: NodeCreatedVia | undefined = args.created_via

// TODO[snikitin@outlook.com] This graph structure has to work somehow
const from_nid: Nid[] = args.from_nid ?? []
const to_nid: Nid[] = args.to_nid ?? []

Expand All @@ -298,6 +299,9 @@ async function createNode(
index_text: args.index_text,
created_at: createdAt,
updated_at: createdAt,
meta: {
uid: account.getUid(),
},
}

let records: YekLav[] = [
Expand Down Expand Up @@ -326,9 +330,7 @@ async function createNode(
crtd: createdAt,
upd: createdAt,
is_sticky: false,
// TODO[snikitin@outlook.com] Evaluate if ownership support is needed
// and implement if yes
owned_by: 'todo',
owned_by: account.getUid(),
}
// Step 1: create records that allow to discover connected nodes from the
// newly created node
Expand Down Expand Up @@ -487,12 +489,9 @@ class Iterator implements INodeIterator {

async function createEdge(
store: YekLavStore,
args: EdgeCreateArgs
args: EdgeCreateArgs,
account: UserAccount
): Promise<TEdge> {
// TODO[snikitin@outlook.com] Evaluate if ownership support is needed
// and implement if yes
const owned_by = 'todo'

const createdAt: number = unixtime.now()
const edge: TEdgeJson = {
eid: generateEid(),
Expand All @@ -501,7 +500,7 @@ async function createEdge(
crtd: createdAt,
upd: createdAt,
is_sticky: false,
owned_by,
owned_by: account.getUid(),
}

const items: YekLav[] = []
Expand Down Expand Up @@ -645,7 +644,8 @@ export async function getAllNids(
}

export function makeBrowserExtStorageApi(
browserStore: browser.Storage.StorageArea
browserStore: browser.Storage.StorageArea,
account: UserAccount
): StorageApi {
const store = new YekLavStore(browserStore)

Expand All @@ -664,7 +664,7 @@ export function makeBrowserExtStorageApi(
getByOrigin: (args: NodeGetByOriginArgs) => getNodesByOrigin(store, args),
getAllNids: (args: NodeGetAllNidsArgs) => getAllNids(store, args),
update: (args: NodeUpdateArgs) => updateNode(store, args),
create: (args: NodeCreateArgs) => createNode(store, args),
create: (args: NodeCreateArgs) => createNode(store, args, account),
iterate: () => new Iterator(store),
delete: throwUnimplementedError('node.delete'),
bulkDelete: throwUnimplementedError('node.bulkdDelete'),
Expand Down Expand Up @@ -692,7 +692,7 @@ export function makeBrowserExtStorageApi(
},
},
edge: {
create: (args: EdgeCreateArgs) => createEdge(store, args),
create: (args: EdgeCreateArgs) => createEdge(store, args, account),
get: (args: EdgeGetArgs) => getNodeAllEdges(store, args),
sticky: throwUnimplementedError('edge.sticky'),
delete: throwUnimplementedError('edge.delete'),
Expand Down
4 changes: 2 additions & 2 deletions truthsayer/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @jsxImportSource @emotion/react */

import React, { useCallback, useContext } from 'react'
import React, { useCallback } from 'react'

import {
BrowserRouter as Router,
Expand Down Expand Up @@ -326,7 +326,7 @@ function PageviewEventTracker({ analytics }: { analytics: PostHog }) {
// See https://posthog.com/docs/integrate/client/js#one-page-apps-and-page-views
// for more information about pageview events in PostHog
analytics.capture('$pageview')
}, [])
}, [analytics])

const history = useHistory()
React.useEffect(() => {
Expand Down
1 change: 0 additions & 1 deletion truthsayer/src/lib/global.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { PostHog } from 'posthog-js'

import { jcss } from 'elementary'
import {
AccountInterface,
makeAlwaysThrowingStorageApi,
makeDatacenterStorageApi,
makeMsgProxyStorageApi,
Expand Down