Skip to content

Commit

Permalink
WIP - #305
Browse files Browse the repository at this point in the history
  • Loading branch information
tegefaulkes committed Feb 17, 2022
1 parent 8cc6c29 commit e9ae9aa
Show file tree
Hide file tree
Showing 3 changed files with 318 additions and 257 deletions.
212 changes: 127 additions & 85 deletions src/vaults/VaultInternal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import type {
CommitId,
CommitLog,
FileSystemReadable,
FileSystemWritable, VaultIdEncoded,
FileSystemWritable,
VaultIdEncoded,
} from './types';
import type { KeyManager } from '../keys';
import type { NodeId, NodeIdEncoded } from '../nodes/types';
Expand All @@ -30,7 +31,7 @@ import { utils as nodesUtils } from '../nodes';

// TODO: Update creation of metadata.
// the use of the remote field needs to be updated so that it is using the
// remote location instead of a boolean. the remote also needs to be proerly
// remote location instead of a boolean. the remote also needs to be properly
// set, likely after calling `start()` in cloneVaultInternal.

// TODO: this might be temp?
Expand Down Expand Up @@ -77,8 +78,7 @@ class VaultInternal {
efs,
logger,
});
vault.vaultName = vaultName
await vault.start({ fresh });
await vault.start({ fresh, vaultName });
logger.info(`Created ${this.name} - ${vaultIdEncoded}`);
return vault;
}
Expand Down Expand Up @@ -125,8 +125,9 @@ class VaultInternal {
// Make the directory where the .git files will be auto generated and
// where the contents will be cloned to ('contents' file)
await efs.mkdir(vault.vaultDataDir, { recursive: true });
let vaultName: VaultName, remoteVaultId: VaultId, remote: RemoteInfo;
try {
const [vaultName, remoteVaultId] = await nodeConnectionManager.withConnF(
[vaultName, remoteVaultId] = await nodeConnectionManager.withConnF(
targetNodeId,
async (connection) => {
const client = connection.getClient();
Expand All @@ -144,14 +145,12 @@ class VaultInternal {
singleBranch: true,
});
return [vaultName, remoteVaultId];
}
},
);
// Fixme, handle name conflict;
vault.vaultName = vaultName;
vault.remote = {
remote = {
remoteNode: nodesUtils.encodeNodeId(targetNodeId),
remoteVault: vaultsUtils.encodeVaultId(remoteVaultId),
}
};
} catch (err) {
// If the error flag set and we have the generalised SmartHttpError from
// isomorphic git then we need to throw the polykey error
Expand All @@ -161,7 +160,13 @@ class VaultInternal {
throw err;
}

await vault.start();
await vault.start({ vaultName });
// Setting the remote in the metadata
await vault.db.put(
vault.vaultMetadataDbDomain,
VaultInternal.remoteKey,
remote,
);
logger.info(`Cloned ${this.name} - ${vaultIdEncoded}`);
return vault;
}
Expand All @@ -179,14 +184,12 @@ class VaultInternal {
protected db: DB;
protected vaultsDbDomain: DBDomain;
protected vaultsDb: DBLevel;
protected vaultDbDomain: DBDomain;
protected vaultDb: DBLevel;
protected vaultMetadataDbDomain: DBDomain;
protected vaultMetadataDb: DBLevel;
protected keyManager: KeyManager;
protected vaultsNamesDomain: DBDomain;
protected efs: EncryptedFS;
protected efsVault: EncryptedFS;
protected vaultName: VaultName | undefined;
protected remote: RemoteInfo | undefined;
protected _lock: Mutex = new Mutex();

public lock: ResourceAcquire<Mutex> = async () => {
Expand Down Expand Up @@ -224,10 +227,17 @@ class VaultInternal {
this.efs = efs;
}

/**
*
* @param fresh Clears all state before starting
* @param vaultName Name of the vault, Only used when creating a new vault
*/
public async start({
fresh = false,
vaultName,
}: {
fresh?: boolean;
vaultName?: VaultName;
} = {}): Promise<void> {
this.logger.info(
`Starting ${this.constructor.name} - ${this.vaultIdEncoded}`,
Expand All @@ -236,11 +246,8 @@ class VaultInternal {
const vaultsNamesDomain = [...this.vaultsDbDomain, 'names'];
const vaultDb = await this.db.level(this.vaultIdEncoded, this.vaultsDb);
// Let's backup any metadata.
this.vaultName = await this.db.get<VaultName>(this.vaultDbDomain, VaultInternal.nameKey) ?? this.vaultName;
if (this.vaultName == null) throw Error(`Temp error, can't have undefined vaultName`);

if (fresh) {
// TODO: remove name->id mapping from VaultManager.
await vaultDb.clear();
try {
await this.efs.rmdir(this.vaultIdEncoded, {
Expand All @@ -255,12 +262,12 @@ class VaultInternal {
await this.efs.mkdir(this.vaultIdEncoded, { recursive: true });
await this.efs.mkdir(this.vaultDataDir, { recursive: true });
await this.efs.mkdir(this.vaultGitDir, { recursive: true });
await this.setupMeta();
await this.setupMeta({ vaultName });
await this.setupGit();
const efsVault = await this.efs.chroot(this.vaultDataDir);
this.vaultDbDomain = vaultDbDomain;
this.vaultMetadataDbDomain = vaultDbDomain;
this.vaultsNamesDomain = vaultsNamesDomain;
this.vaultDb = vaultDb;
this.vaultMetadataDb = vaultDb;
this.efsVault = efsVault;
this.logger.info(
`Started ${this.constructor.name} - ${this.vaultIdEncoded}`,
Expand Down Expand Up @@ -375,38 +382,50 @@ class VaultInternal {
public readG<T, TReturn, TNext>(
g: (fs: FileSystemReadable) => AsyncGenerator<T, TReturn, TNext>,
): AsyncGenerator<T, TReturn, TNext> {
const efsVault = this.efsVault;
return withG([this.lock], async function* () {
return yield* g(this.efsVault);
return yield* g(efsVault);
});
}

@ready(new vaultsErrors.ErrorVaultNotRunning())
public async writeF(
f: (fs: FileSystemWritable) => Promise<void>,
): Promise<void> {
// This should really be an internal property
// get whether this is remote, and the remote address
// if it is, we consider this repo an "attached repo"
// this vault is a "mirrored" vault
if (
(await this.db.get(
this.vaultMetadataDbDomain,
VaultInternal.remoteKey,
)) != null
) {
// Mirrored vaults are immutable
throw new vaultsErrors.ErrorVaultImmutable();
}
return withF([this.lock], async () => {
await this.db.put(this.vaultsDbDomain, VaultInternal.dirtyKey, true);
// This should really be an internal property
// get whether this is remote, and the remote address
// if it is, we consider this repo an "attached repo"
// this vault is a "mirrored" vault
if (this.remote) {
// Mirrored vaults are immutable
throw new vaultsErrors.ErrorVaultImmutable();
}
await this.db.put(
this.vaultMetadataDbDomain,
VaultInternal.dirtyKey,
true,
);

// We have to chroot it
// and then remove it
// but this is done byitself?

// but this is done by itself?
await f(this.efsVault);

await this.db.put(this.vaultsDbDomain, VaultInternal.dirtyKey, false);
await this.db.put(
this.vaultMetadataDbDomain,
VaultInternal.dirtyKey,
false,
);
});

// Const message: string[] = [];
// try {

//
// // If the version of the vault has been changed, checkout the working
// // directory to this point in history and discard any unlinked commits
// await git.checkout({
Expand Down Expand Up @@ -555,23 +574,32 @@ class VaultInternal {
public writeG<T, TReturn, TNext>(
g: (fs: FileSystemWritable) => AsyncGenerator<T, TReturn, TNext>,
): AsyncGenerator<T, TReturn, TNext> {
const efsVault = this.efsVault;
const db = this.db;
const vaultDbDomain = this.vaultMetadataDbDomain;
return withG([this.lock], async function* () {
const result = yield* g(this.efsVault);
// At the end of the geneartor
if ((await db.get(vaultDbDomain, VaultInternal.remoteKey)) != null) {
// Mirrored vaults are immutable
throw new vaultsErrors.ErrorVaultImmutable();
}
await db.put(vaultDbDomain, VaultInternal.dirtyKey, true);
const result = yield* g(efsVault);
// At the end of the generator
// you need to do this
// but just before
// you need to finish it up

// DO what you need to do here, create the commit
await db.put(vaultDbDomain, VaultInternal.dirtyKey, false);
return result;
});
}

@ready(new vaultsErrors.ErrorVaultNotRunning())
public async pullVault({
nodeConnectionManager,
pullNodeId,
pullVaultNameOrId,
nodeConnectionManager,
pullNodeId,
pullVaultNameOrId,
}: {
nodeConnectionManager: NodeConnectionManager;
pullNodeId?: NodeId;
Expand All @@ -584,23 +612,26 @@ class VaultInternal {
let metaChange = 0;
const thisNodeId = this.keyManager.getNodeId();
// TODO: get proper metadata.
let remoteNode = {} as NodeId;
let remoteVault = '';
const remoteInfo = await this.db.get<RemoteInfo>(
this.vaultMetadataDbDomain,
VaultInternal.remoteKey,
);
if (remoteInfo == null) throw Error('Vault has no remote to pull from');

if (pullNodeId == null) {
pullNodeId = remoteNode;
pullNodeId = nodesUtils.decodeNodeId(remoteInfo.remoteNode)!;
} else {
metaChange = 1;
remoteNode = pullNodeId;
remoteInfo.remoteNode = nodesUtils.encodeNodeId(pullNodeId);
}
if (pullVaultNameOrId == null) {
pullVaultNameOrId = vaultsUtils.decodeVaultId(remoteVault!);
pullVaultNameOrId = vaultsUtils.decodeVaultId(remoteInfo.remoteVault!);
} else {
metaChange = 1;
if (typeof pullVaultNameOrId === 'string') {
metaChange = 2;
} else {
remoteVault = pullVaultNameOrId.toString();
remoteInfo.remoteVault = vaultsUtils.encodeVaultId(pullVaultNameOrId);
}
}
this.logger.info(
Expand All @@ -610,27 +641,30 @@ class VaultInternal {
);
let remoteVaultId: VaultIdEncoded;
try {
remoteVaultId = await nodeConnectionManager.withConnF(pullNodeId!, async (connection) => {
const client = connection.getClient();
const [request, , remoteVaultId] = await vaultsUtils.request(
client,
thisNodeId,
pullVaultNameOrId!,
);
await git.pull({
fs: this.efs,
http: { request },
dir: this.vaultDataDir,
gitdir: this.vaultGitDir,
url: `http://`,
ref: 'HEAD',
singleBranch: true,
author: {
name: nodesUtils.encodeNodeId(pullNodeId!),
},
});
return remoteVaultId;
});
remoteVaultId = await nodeConnectionManager.withConnF(
pullNodeId!,
async (connection) => {
const client = connection.getClient();
const [request, , remoteVaultId] = await vaultsUtils.request(
client,
thisNodeId,
pullVaultNameOrId!,
);
await git.pull({
fs: this.efs,
http: { request },
dir: this.vaultDataDir,
gitdir: this.vaultGitDir,
url: `http://`,
ref: 'HEAD',
singleBranch: true,
author: {
name: nodesUtils.encodeNodeId(pullNodeId!),
},
});
return remoteVaultId;
},
);
} catch (err) {
// If the error flag set and we have the generalised SmartHttpError from
// isomorphic git then we need to throw the polykey error
Expand All @@ -644,8 +678,12 @@ class VaultInternal {
throw err;
}
if (metaChange !== 0) {
if (metaChange === 2) remoteVault = remoteVaultId;
// TODO: update remote metadata here.
if (metaChange === 2) remoteInfo.remoteVault = remoteVaultId;
await this.db.put(
this.vaultMetadataDbDomain,
VaultInternal.remoteKey,
remoteInfo,
);
}
this.logger.info(
`Pulled Vault ${vaultsUtils.encodeVaultId(
Expand All @@ -657,33 +695,37 @@ class VaultInternal {
/**
* Setup the vault metadata
*/
protected async setupMeta(
): Promise<void> {
protected async setupMeta({
vaultName,
}: {
vaultName?: VaultName;
}): Promise<void> {
// Setup the vault metadata
// and you need to make certain preparations
// the meta gets created first
// if the SoT is the database
// are we supposed to check this?

// If this is not existing
// Update remote
if (this.remote != null){
await this.db.put(this.vaultDbDomain, VaultInternal.remoteKey, this.remote);
}

// setup default vaults db
if (await this.db.get<boolean>(this.vaultDbDomain, VaultInternal.dirtyKey) == null) {
if (
(await this.db.get<boolean>(
this.vaultMetadataDbDomain,
VaultInternal.dirtyKey,
)) == null
) {
await this.db.put(this.vaultsDbDomain, VaultInternal.dirtyKey, true);
}

// Set up vault Name
if (await this.db.get<string>(this.vaultDbDomain, VaultInternal.nameKey) == null && this.vaultName != null) {
await this.db.put(this.vaultsDbDomain, VaultInternal.nameKey, this.vaultName);
}

// Setting reverse mapping.
if (this.vaultName != null && await this.db.get<string>(this.vaultsNamesDomain, this.vaultName) == null) {
await this.db.put(this.vaultsNamesDomain, this.vaultName, this.vaultIdEncoded);
if (
(await this.db.get<string>(
this.vaultMetadataDbDomain,
VaultInternal.nameKey,
)) == null &&
vaultName != null
) {
await this.db.put(this.vaultsDbDomain, VaultInternal.nameKey, vaultName);
}

// Remote: [NodeId, VaultId] | undefined
Expand Down
Loading

0 comments on commit e9ae9aa

Please sign in to comment.