diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..e8f192171 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,55 @@ +stages: + - build + - test + - docker + - deploy + +# include private configs for the remaining stages +include: + - project: "it/ci-config" + file: "/testnet/deploy_webapp.yml" + +variables: + # nginx configuration for this webapp + NGINX_CONFIG: | + server { + listen 80; + listen [::]:80; + server_name localhost; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $$uri $$uri/ =404; + } + } + +build: + stage: build + image: node:lts + artifacts: + paths: + - dist/ + cache: + key: node-cache + paths: + - node_modules/ + script: + - yarn install + - yarn build + # Make sure the dist directory exists, so that _this_ job fails and not the next one + - test -d dist || (echo "No dist directory\!" && exit 1) + - test -f dist/index.html || (echo "No files in dist\!" && exit 1) + allow_failure: false + +test: + stage: test + image: node:lts + cache: + key: node-cache + paths: + - node_modules/ + script: + - yarn lint + allow_failure: true + diff --git a/client/src/RequestBehavior.ts b/client/src/RequestBehavior.ts index 9eca4fed5..804714879 100644 --- a/client/src/RequestBehavior.ts +++ b/client/src/RequestBehavior.ts @@ -64,39 +64,27 @@ export class RedirectRequestBehavior extends RequestBehavior { export class IFrameRequestBehavior extends RequestBehavior { private static IFRAME_PATH_SUFFIX = '/request/iframe/'; - private _iframe: HTMLIFrameElement | null; - private _client: PostMessageRpcClient | null; + private _iframeEndpoint: string | null = null; + private _iframePromise: Promise | null = null; + private _clientPromise: Promise | null = null; constructor() { super(BehaviorType.IFRAME); - this._iframe = null; - this._client = null; } public async request(endpoint: string, command: KeyguardCommand, args: any[]): Promise { - if (this._iframe && this._iframe.src !== `${endpoint}${IFrameRequestBehavior.IFRAME_PATH_SUFFIX}`) { - throw new Error('Keyguard iframe is already opened with another endpoint'); - } - - const origin = RequestBehavior.getAllowedOrigin(endpoint); - - if (!this._iframe) { - this._iframe = await this.createIFrame(endpoint); - } - if (!this._iframe.contentWindow) { - throw new Error(`IFrame contentWindow is ${typeof this._iframe.contentWindow}`); - } - - if (!this._client) { - this._client = new PostMessageRpcClient(this._iframe.contentWindow, origin); - await this._client.init(); - } - - return await this._client.call(command, ...args); + const client = await this._getClient(endpoint); + return client.call(command, ...args); } public async createIFrame(endpoint: string): Promise { - return new Promise((resolve, reject) => { + if (this._iframeEndpoint && this._iframeEndpoint !== endpoint) { + throw new Error('Keyguard iframe is already opened with another endpoint' + + `(opened: ${this._iframeEndpoint}, expected: ${endpoint})`); + } + this._iframeEndpoint = endpoint; + + this._iframePromise = this._iframePromise || new Promise((resolve, reject) => { const $iframe = document.createElement('iframe'); $iframe.name = 'NimiqKeyguardIFrame'; $iframe.style.display = 'none'; @@ -104,6 +92,25 @@ export class IFrameRequestBehavior extends RequestBehavior { $iframe.src = `${endpoint}${IFrameRequestBehavior.IFRAME_PATH_SUFFIX}`; $iframe.onload = () => resolve($iframe); $iframe.onerror = reject; - }) as Promise; + }); + + return this._iframePromise; + } + + private _getClient(endpoint: string): Promise { + this._clientPromise = this._clientPromise || new Promise(async (resolve) => { + const iframe = await this.createIFrame(endpoint); + if (!iframe.contentWindow) { + throw new Error(`IFrame contentWindow is ${typeof iframe.contentWindow}`); + } + + const origin = RequestBehavior.getAllowedOrigin(endpoint); + const client = new PostMessageRpcClient(iframe.contentWindow, origin); + await client.init(); + + resolve(client); + }); + + return this._clientPromise; } }