import { WORKER_REQUEST_READ_LOCK, WORKER_RELEASE_READ_LOCK, MASTER_GRANT_READ_LOCK, WORKER_REQUEST_WRITE_LOCK, WORKER_RELEASE_WRITE_LOCK, MASTER_GRANT_WRITE_LOCK, WORKER_ABORT_READ_LOCK_REQUEST, WORKER_ABORT_WRITE_LOCK_REQUEST, MASTER_READ_LOCK_ERROR, MASTER_WRITE_LOCK_ERROR, WORKER_FINALIZE, BROADCAST_CHANNEL_NAME } from '../constants.js';
import { nanoid } from '../utils.js';
export class MorticeChannelWorker {
    name;
    channel;
    constructor(name) {
        this.name = name;
        this.channel = new BroadcastChannel(BROADCAST_CHANNEL_NAME);
    }
    readLock(options) {
        return this.sendRequest(WORKER_REQUEST_READ_LOCK, WORKER_ABORT_READ_LOCK_REQUEST, MASTER_GRANT_READ_LOCK, MASTER_READ_LOCK_ERROR, WORKER_RELEASE_READ_LOCK, options);
    }
    writeLock(options) {
        return this.sendRequest(WORKER_REQUEST_WRITE_LOCK, WORKER_ABORT_WRITE_LOCK_REQUEST, MASTER_GRANT_WRITE_LOCK, MASTER_WRITE_LOCK_ERROR, WORKER_RELEASE_WRITE_LOCK, options);
    }
    finalize() {
        this.channel.postMessage({
            type: WORKER_FINALIZE,
            name: this.name
        });
        this.channel.close();
    }
    async sendRequest(requestType, abortType, grantType, errorType, releaseType, options) {
        options?.signal?.throwIfAborted();
        const id = nanoid();
        this.channel.postMessage({
            type: requestType,
            identifier: id,
            name: this.name
        });
        return new Promise((resolve, reject) => {
            const abortListener = () => {
                this.channel.postMessage({
                    type: abortType,
                    identifier: id,
                    name: this.name
                });
            };
            options?.signal?.addEventListener('abort', abortListener, {
                once: true
            });
            const listener = (event) => {
                if (event.data?.identifier !== id) {
                    return;
                }
                if (event.data?.type === grantType) {
                    this.channel.removeEventListener('message', listener);
                    options?.signal?.removeEventListener('abort', abortListener);
                    // lock granted
                    resolve(() => {
                        // release lock
                        this.channel.postMessage({
                            type: releaseType,
                            identifier: id,
                            name: this.name
                        });
                    });
                }
                if (event.data.type === errorType) {
                    this.channel.removeEventListener('message', listener);
                    options?.signal?.removeEventListener('abort', abortListener);
                    // error while waiting for grant of lock
                    const err = new Error();
                    if (event.data.error != null) {
                        err.message = event.data.error.message;
                        err.name = event.data.error.name;
                        err.stack = event.data.error.stack;
                    }
                    reject(err);
                }
            };
            this.channel.addEventListener('message', listener);
        });
    }
}
//# sourceMappingURL=channel.js.map