Skip to content

Commit

Permalink
Removed temporary hack
Browse files Browse the repository at this point in the history
  • Loading branch information
thehenrytsai committed Jul 5, 2024
1 parent d5dd21b commit 022d4a0
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 66 deletions.
47 changes: 31 additions & 16 deletions src/dwn-server.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
import type { DidResolver } from '@web5/dids';
import type { EventStream } from '@tbd54566975/dwn-sdk-js';
import { Dwn, EventEmitterStream } from '@tbd54566975/dwn-sdk-js';

import type { ProcessHandlers } from './process-handlers.js';
import type { Server } from 'http';
import type { WebSocketServer } from 'ws';
import type { DwnServerConfig } from './config.js';

import log from 'loglevel';
import prefix from 'loglevel-plugin-prefix';
import { type WebSocketServer } from 'ws';

import { config as defaultConfig } from './config.js';
import { getDWNConfig } from './storage.js';
import { HttpServerShutdownHandler } from './lib/http-server-shutdown-handler.js';

import { type DwnServerConfig, config as defaultConfig } from './config.js';
import { HttpApi } from './http-api.js';
import { setProcessHandlers, unsetProcessHandlers } from './process-handlers.js';
import { getDWNConfig } from './storage.js';
import { WsApi } from './ws-api.js';
import { RegistrationManager } from './registration/registration-manager.js';
import { WsApi } from './ws-api.js';
import { Dwn, EventEmitterStream } from '@tbd54566975/dwn-sdk-js';
import { setProcessHandlers, unsetProcessHandlers } from './process-handlers.js';

/**
* Options for the DwnServer constructor.
* This is different to DwnServerConfig in that the DwnServerConfig defines configuration that come from environment variables so (more) user facing.
* Where as DwnServerOptions wraps DwnServerConfig with additional overrides that can be used for testing.
*/
export type DwnServerOptions = {
/**
* A custom DID resolver to use in the DWN.
* Mainly for testing purposes. Ignored if `dwn` is provided.
*/
didResolver?: DidResolver;
dwn?: Dwn;
config?: DwnServerConfig;
};
Expand All @@ -29,6 +39,12 @@ export enum DwnServerState {
export class DwnServer {
serverState = DwnServerState.Stopped;
processHandlers: ProcessHandlers;

/**
* A custom DID resolver to use in the DWN.
* Mainly for testing purposes. Ignored if `dwn` is provided.
*/
didResolver?: DidResolver;
dwn?: Dwn;
config: DwnServerConfig;
#httpServerShutdownHandler: HttpServerShutdownHandler;
Expand All @@ -40,6 +56,8 @@ export class DwnServer {
*/
constructor(options: DwnServerOptions = {}) {
this.config = options.config ?? defaultConfig;

this.didResolver = options.didResolver;
this.dwn = options.dwn;

log.setLevel(this.config.logLevel as log.LogLevelDesc);
Expand Down Expand Up @@ -84,10 +102,12 @@ export class DwnServer {
eventStream = new EventEmitterStream();
}

this.dwn = await Dwn.create(getDWNConfig(this.config, {
const dwnConfig = getDWNConfig(this.config, {
didResolver: this.didResolver,
tenantGate: registrationManager,
eventStream,
}));
})
this.dwn = await Dwn.create(dwnConfig);
}

this.#httpApi = await HttpApi.create(this.config, this.dwn, registrationManager);
Expand All @@ -114,11 +134,6 @@ export class DwnServer {
return;
}

// F YEAH!
if (this.dwn['didResolver']['cache']['cache']) {
await this.dwn['didResolver']['cache']['cache']['close']();
}

await this.dwn.close();
await this.#httpApi.stop();

Expand Down
6 changes: 4 additions & 2 deletions src/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
MessageStoreLevel,
ResumableTaskStoreLevel,
} from '@tbd54566975/dwn-sdk-js';
import type { DidResolver } from '@web5/dids';
import type {
DataStore,
DwnConfig,
Expand Down Expand Up @@ -52,17 +53,18 @@ export type StoreType = DataStore | EventLog | MessageStore | ResumableTaskStore
export function getDWNConfig(
config : DwnServerConfig,
options : {
didResolver? : DidResolver,
tenantGate? : TenantGate,
eventStream? : EventStream,
}
): DwnConfig {
const { tenantGate, eventStream } = options;
const { tenantGate, eventStream, didResolver } = options;
const dataStore: DataStore = getStore(config.dataStore, EStoreType.DataStore);
const eventLog: EventLog = getStore(config.eventLog, EStoreType.EventLog);
const messageStore: MessageStore = getStore(config.messageStore, EStoreType.MessageStore);
const resumableTaskStore: ResumableTaskStore = getStore(config.messageStore, EStoreType.ResumableTaskStore);

return { eventStream, eventLog, dataStore, messageStore, resumableTaskStore, tenantGate };
return { didResolver, eventStream, eventLog, dataStore, messageStore, resumableTaskStore, tenantGate };
}

function getLevelStore(
Expand Down
83 changes: 36 additions & 47 deletions tests/scenarios/registration.spec.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,26 @@
import type { DwnServerConfig } from '../../src/config.js';
import type { Persona } from '@tbd54566975/dwn-sdk-js';
import fetch from 'node-fetch';
import type { ProofOfWorkChallengeModel } from '../../src/registration/proof-of-work-types.js';
import type { RegistrationManager } from '../../src/registration/registration-manager.js';
import type { JsonRpcRequest, JsonRpcResponse } from '../../src/lib/json-rpc.js';
import type { RegistrationData, RegistrationRequest } from '../../src/registration/registration-types.js';

import fetch from 'node-fetch';
import { config } from '../../src/config.js';
import { createJsonRpcRequest} from '../../src/lib/json-rpc.js';
import { createRecordsWriteMessage } from '../utils.js';
import { DwnServer } from '../../src/dwn-server.js';
import { DwnServerErrorCode } from '../../src/dwn-error.js';
import { expect } from 'chai';
import { ProofOfWork } from '../../src/registration/proof-of-work.js';
import { ProofOfWorkManager } from '../../src/registration/proof-of-work-manager.js';
import { randomBytes } from 'crypto';
import { readFileSync } from 'fs';
import { webcrypto } from 'node:crypto';
import { useFakeTimers } from 'sinon';
import { v4 as uuidv4 } from 'uuid';
import { webcrypto } from 'node:crypto';
import { DataStream, TestDataGenerator } from '@tbd54566975/dwn-sdk-js';

import type { DwnServerConfig } from '../../src/config.js';
import { config } from '../../src/config.js';
import type {
JsonRpcRequest,
JsonRpcResponse,
} from '../../src/lib/json-rpc.js';
import {
createJsonRpcRequest,
} from '../../src/lib/json-rpc.js';
import { ProofOfWork } from '../../src/registration/proof-of-work.js';
import {
createRecordsWriteMessage,
} from '../utils.js';
import type { ProofOfWorkChallengeModel } from '../../src/registration/proof-of-work-types.js';
import type { RegistrationData, RegistrationRequest } from '../../src/registration/registration-types.js';
import type { RegistrationManager } from '../../src/registration/registration-manager.js';
import { DwnServerErrorCode } from '../../src/dwn-error.js';
import { ProofOfWorkManager } from '../../src/registration/proof-of-work-manager.js';
import { DwnServer } from '../../src/dwn-server.js';
import { randomBytes } from 'crypto';
import { DidDht, DidKey, UniversalResolver } from '@web5/dids';

// node.js 18 and earlier, needs globalThis.crypto polyfill
if (!globalThis.crypto) {
Expand Down Expand Up @@ -65,7 +58,16 @@ describe('Registration scenarios', function () {
dwnServerConfig.termsOfServiceFilePath = './tests/fixtures/terms-of-service.txt';
dwnServerConfig.registrationProofOfWorkInitialMaxHash = '0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'; // 1 in 16 chance of solving

dwnServer = new DwnServer({ config: dwnServerConfig });
// CRITICAL: We need to create a custom DID resolver that does not use a LevelDB based cache (which is the default cache used in `DWN`)
// otherwise we will receive a `Database is not open` coming from LevelDB.
// This is likely due to the fact that LevelDB is the default cache used in `DWN`, and we have tests creating default DWN instances,
// so here we have to create a DWN that does not use the same LevelDB cache to avoid hitting LevelDB locked issues.
// Long term we should investigate and unify approach of DWN instantiation taken by tests to avoid this "workaround" entirely.
const didResolver = new UniversalResolver({
didResolvers : [DidDht, DidKey],
});

dwnServer = new DwnServer({ config: dwnServerConfig, didResolver });
await dwnServer.start();
registrationManager = dwnServer.registrationManager;
});
Expand All @@ -74,22 +76,6 @@ describe('Registration scenarios', function () {
clock.restore();
});

beforeEach(async () => {
// sinon.restore(); // wipe all previous stubs/spies/mocks/fakes/clock

// // IMPORTANT: MUST be called AFTER `sinon.restore()` because `sinon.restore()` resets fake timers
// clock = useFakeTimers({ shouldAdvanceTime: true });

// dwnServer = new DwnServer({ config: dwnServerConfig });
// await dwnServer.start();
// registrationManager = dwnServer.registrationManager;
});

afterEach(async () =>{
// await dwnServer.registrationManager['registrationStore']['db'].destroy();
// await dwnServer.stop();
});

it('should facilitate tenant registration with terms-of-service and proof-or-work turned on', async () => {
// Scenario:
// 1. Alice fetches the terms-of-service.
Expand Down Expand Up @@ -540,11 +526,6 @@ describe('Registration scenarios', function () {

});

/**
* NOTE: The tests below instantiate their own server configs and should should take care to stop the `dwnServer`
* This is done to avoid LevelDB locking for the default `DidResolver` cache.
*/

it('should initialize ProofOfWorkManager with challenge nonce seed if given.', async function () {
await dwnServer.stop();

Expand All @@ -563,7 +544,15 @@ describe('Registration scenarios', function () {

it('should allow tenant registration to be turned off to allow all DWN messages through.', async () => {
await dwnServer.stop();
// await dwnServer.registrationManager['registrationStore']['db'].destroy();

// CRITICAL: We need to create a custom DID resolver that does not use a LevelDB based cache (which is the default cache used in `DWN`)
// otherwise we will receive a `Database is not open` coming from LevelDB.
// This is likely due to the fact that LevelDB is the default cache used in `DWN`, and we have tests creating default DWN instances,
// so here we have to create a DWN that does not use the same LevelDB cache to avoid hitting LevelDB locked issues.
// Long term we should investigate and unify approach of DWN instantiation taken by tests to avoid this "workaround" entirely.
const didResolver = new UniversalResolver({
didResolvers : [DidDht, DidKey],
});

// Scenario:
// 1. There is a DWN that does not require tenant registration.
Expand All @@ -575,7 +564,7 @@ describe('Registration scenarios', function () {
registrationProofOfWorkEnabled: false,
termsOfServiceFilePath: undefined,
};
dwnServer = new DwnServer({ config: configClone });
dwnServer = new DwnServer({ config: configClone, didResolver });
await dwnServer.start();

const { jsonRpcRequest, dataBytes } = await generateRecordsWriteJsonRpcRequest(alice);
Expand Down
2 changes: 1 addition & 1 deletion tests/scenarios/web5-connect.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('Web5 Connect scenarios', function () {

before(async function () {

// NOTE: using SQL to workaround an issue where multiple instances of DwnServer can be started using LevelDB in the same test run,
// NOTE: using SQL to workaround an issue where multiple instances of DwnServer cannot be started using LevelDB in the same test run,
// and dwn-server.spec.ts already uses LevelDB.
dwnServerConfig.messageStore = 'sqlite://',
dwnServerConfig.dataStore = 'sqlite://',
Expand Down

0 comments on commit 022d4a0

Please sign in to comment.