/*
* Copyright 2023, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and/or binary forms, with or without
* modification, must retain the above copyright notice and the following
* disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
"use strict";
import {ActorRequestFactory} from './actor-request-factory';
import {AnyPacker} from "./any-packer";
import {AbstractClientFactory} from './client-factory';
import {CommandingClient} from "./commanding-client";
import {CompositeClient} from "./composite-client";
import {HttpClient} from './http-client';
import {HttpEndpoint} from './http-endpoint';
import KnownTypes from "./known-types";
import {QueryingClient} from "./querying-client";
import {NoOpSubscribingClient} from "./subscribing-client";
import {Type} from "./typed-message";
import TypeParsers from "./parser/type-parsers";
/**
* An implementation of the `AbstractClientFactory` that creates instances of client which exchanges
* data with the server directly.
*
* Querying is performed by sending a query to the server over HTTP and reading the query response
* from the HTTP response.
*
* This client does not support subscriptions.
*/
export class DirectClientFactory extends AbstractClientFactory {
static _clientFor(options) {
const httpClient = this._createHttpClient(options);
const httpResponseHandler = this._createHttpResponseHandler(options);
const endpoint = new HttpEndpoint(httpClient, httpResponseHandler, options.routing);
const requestFactory = ActorRequestFactory.create(options);
const querying = new DirectQueryingClient(endpoint, requestFactory);
const subscribing = new NoOpSubscribingClient(requestFactory);
const commanding = new CommandingClient(endpoint, requestFactory);
return new CompositeClient(querying, subscribing, commanding);
}
static createQuerying(options) {
const httpClient = this._createHttpClient(options);
const httpResponseHandler = this._createHttpResponseHandler(options);
const endpoint = new HttpEndpoint(httpClient, httpResponseHandler, options.routing);
const requestFactory = ActorRequestFactory.create(options);
return new DirectQueryingClient(endpoint, requestFactory);
}
static createSubscribing(options) {
const requestFactory = ActorRequestFactory.create(options);
return new NoOpSubscribingClient(requestFactory);
}
/**
* @override
*/
static _ensureOptionsSufficient(options) {
super._ensureOptionsSufficient(options);
const messageForMissing = (option) =>
`Unable to initialize a direct client. The ClientOptions.${option} not specified.`;
if (!options.endpointUrl) {
throw new Error(messageForMissing('endpointUrl'));
}
if (!options.actorProvider) {
throw new Error(messageForMissing('actorProvider'));
}
}
}
/**
* A {@link QueryingClient} which reads entity states directly from the server.
*/
class DirectQueryingClient extends QueryingClient {
/**
* An internal `DirectQueryingClient` constructor.
*
* Use `FirebaseClient#usingFirebase()` for instantiation.
*
* @param {!HttpEndpoint} endpoint the server endpoint to execute queries and commands
* @param {!ActorRequestFactory} actorRequestFactory a factory to instantiate the actor requests with
*
* @protected
*/
constructor(endpoint, actorRequestFactory) {
super(actorRequestFactory);
this._endpoint = endpoint;
}
read(query) {
const typeUrl = query.getTarget().getType();
const targetClass = KnownTypes.classFor(typeUrl);
const targetType = Type.of(targetClass, typeUrl);
const responseParser = TypeParsers.parserFor('type.spine.io/spine.client.QueryResponse');
return this._endpoint
.query(query)
.then(response => {
const message = responseParser.fromObject(response);
const entityStates = message.getMessageList();
return entityStates.map(entity => DirectQueryingClient._unpack(entity, targetType));
});
}
static _unpack(entity, targetType) {
const unpacker = AnyPacker.unpack(entity.getState());
return unpacker.as(targetType);
}
}