pass in the cors proxy endpoint
This commit is contained in:
parent
6dc835d080
commit
8d7ddddd78
|
@ -4,6 +4,6 @@ export class SourceSyncMessage {
|
|||
source: Source
|
||||
current_user: string
|
||||
couchdb_endpoint_base: string
|
||||
|
||||
fasten_api_endpoint_base: string
|
||||
response?: any
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ export class QueueService {
|
|||
sourceSync.source = source
|
||||
sourceSync.current_user = this.fastenDbService.current_user
|
||||
sourceSync.couchdb_endpoint_base = environment.couchdb_endpoint_base
|
||||
sourceSync.fasten_api_endpoint_base = environment.fasten_api_endpoint_base
|
||||
const input$: Observable<string> = of(JSON.stringify(sourceSync));
|
||||
return fromWorker<string, string>(() => new Worker(new URL('./source-sync.worker', import.meta.url), {type: 'module'}), input$)
|
||||
// .subscribe(message => {
|
||||
|
|
|
@ -7,6 +7,8 @@ import {SourceSyncMessage} from '../models/queue/source-sync-message';
|
|||
import {NewPouchdbRepositoryWebWorker, PouchdbRepository} from '../../lib/database/pouchdb_repository';
|
||||
import {NewClient} from '../../lib/conduit/factory';
|
||||
import {Source} from '../../lib/models/database/source';
|
||||
import {ClientConfig} from '../../lib/models/client/client-config';
|
||||
import {client} from 'fhirclient';
|
||||
|
||||
export class SourceSyncWorker implements DoWork<string, string> {
|
||||
public work(input$: Observable<string>): Observable<string> {
|
||||
|
@ -19,7 +21,10 @@ export class SourceSyncWorker implements DoWork<string, string> {
|
|||
const sourceSyncMessage = JSON.parse(msg) as SourceSyncMessage
|
||||
|
||||
const db = NewPouchdbRepositoryWebWorker(sourceSyncMessage.current_user, sourceSyncMessage.couchdb_endpoint_base)
|
||||
const client = NewClient(sourceSyncMessage.source.source_type, new Source(sourceSyncMessage.source))
|
||||
|
||||
let clientConfig = new ClientConfig()
|
||||
clientConfig.fasten_api_endpoint_base = sourceSyncMessage.fasten_api_endpoint_base
|
||||
const client = NewClient(sourceSyncMessage.source.source_type, new Source(sourceSyncMessage.source), clientConfig)
|
||||
//TODO: validate the FHIR version from the datasource matches the client
|
||||
// if the source token has been refreshed, we need to store it in the DB.
|
||||
// await db.UpsertSource()
|
||||
|
|
|
@ -10,28 +10,29 @@ import {CignaClient} from './fhir/cigna_client';
|
|||
import {EpicClient} from './fhir/epic_client';
|
||||
import {HealthITClient} from './fhir/healthit_client';
|
||||
import {LogicaClient} from './fhir/logica_client';
|
||||
import {ClientConfig} from '../models/client/client-config';
|
||||
|
||||
export function NewClient(sourceType: SourceType, source: Source): IClient {
|
||||
export function NewClient(sourceType: SourceType, source: Source, clientConfig: ClientConfig): IClient {
|
||||
|
||||
switch(sourceType) {
|
||||
case SourceType.Aetna:
|
||||
return new AetnaClient(source)
|
||||
return new AetnaClient(source, clientConfig)
|
||||
case SourceType.Athena:
|
||||
return new AthenaClient(source)
|
||||
return new AthenaClient(source, clientConfig)
|
||||
case SourceType.BlueButtonMedicare:
|
||||
return new BlueButtonClient(source)
|
||||
return new BlueButtonClient(source, clientConfig)
|
||||
case SourceType.CareEvolution:
|
||||
return new CareEvolutionClient(source)
|
||||
return new CareEvolutionClient(source, clientConfig)
|
||||
case SourceType.Cerner:
|
||||
return new CernerClient(source)
|
||||
return new CernerClient(source, clientConfig)
|
||||
case SourceType.Cigna:
|
||||
return new CignaClient(source)
|
||||
return new CignaClient(source, clientConfig)
|
||||
case SourceType.Epic:
|
||||
return new EpicClient(source)
|
||||
return new EpicClient(source, clientConfig)
|
||||
case SourceType.HealthIT:
|
||||
return new HealthITClient(source)
|
||||
return new HealthITClient(source, clientConfig)
|
||||
case SourceType.Logica:
|
||||
return new LogicaClient(source)
|
||||
return new LogicaClient(source, clientConfig )
|
||||
// case SourceType.Manual:
|
||||
// return new ManualClient(source)
|
||||
default:
|
||||
|
|
|
@ -3,10 +3,11 @@ import {FHIR401Client} from './base/fhir401_r4_client';
|
|||
import {Source} from '../../models/database/source';
|
||||
import {IDatabaseRepository} from '../../database/interface';
|
||||
import {UpsertSummary} from '../../models/fasten/upsert-summary';
|
||||
import {ClientConfig} from '../../models/client/client-config';
|
||||
|
||||
export class AetnaClient extends FHIR401Client implements IClient {
|
||||
constructor(source: Source) {
|
||||
super(source);
|
||||
constructor(source: Source, clientConfig: ClientConfig) {
|
||||
super(source, clientConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,10 +3,11 @@ import {FHIR401Client} from './base/fhir401_r4_client';
|
|||
import {Source} from '../../models/database/source';
|
||||
import {IDatabaseRepository} from '../../database/interface';
|
||||
import {UpsertSummary} from '../../models/fasten/upsert-summary';
|
||||
import {ClientConfig} from '../../models/client/client-config';
|
||||
|
||||
export class AthenaClient extends FHIR401Client implements IClient {
|
||||
constructor(source: Source) {
|
||||
super(source);
|
||||
constructor(source: Source, clientConfig: ClientConfig) {
|
||||
super(source, clientConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import {Source} from '../../../models/database/source';
|
||||
import * as Oauth from '@panva/oauth4webapi';
|
||||
import {IResourceRaw} from '../../interface';
|
||||
import {GetEndpointAbsolutePath} from '../../../utils/endpoint_absolute_path';
|
||||
import {ClientConfig} from '../../../models/client/client-config';
|
||||
|
||||
|
||||
class SourceUpdateStatus {
|
||||
|
@ -11,13 +13,16 @@ class SourceUpdateStatus {
|
|||
// BaseClient is an abstract/partial class, its intended to be used by FHIR clients, and generically handle OAuth requests.
|
||||
export abstract class BaseClient {
|
||||
|
||||
private clientConfig: ClientConfig
|
||||
private oauthClient: Oauth.Client
|
||||
private oauthAuthorizationServer: Oauth.AuthorizationServer
|
||||
public source: Source
|
||||
public headers: Headers
|
||||
|
||||
protected constructor(source: Source) {
|
||||
|
||||
protected constructor(source: Source, clientConfig: ClientConfig) {
|
||||
this.source = source
|
||||
this.clientConfig = clientConfig
|
||||
this.headers = new Headers()
|
||||
|
||||
//init Oauth client based on source configuration
|
||||
|
@ -65,7 +70,7 @@ export abstract class BaseClient {
|
|||
//this endpoint requires a CORS relay
|
||||
//get the path to the Fasten server, and append `cors/` and then append the request url
|
||||
let resourceParts = new URL(resourceUrl)
|
||||
resourceUrl = this.getCORSProxyPath() + `${resourceParts.hostname}${resourceParts.pathname}${resourceParts.search}`
|
||||
resourceUrl = GetEndpointAbsolutePath(globalThis.location, this.clientConfig.fasten_api_endpoint_base) + `/${resourceParts.hostname}${resourceParts.pathname}${resourceParts.search}`
|
||||
}
|
||||
|
||||
|
||||
|
@ -144,11 +149,4 @@ export abstract class BaseClient {
|
|||
return sourceUpdateStatus
|
||||
})
|
||||
}
|
||||
|
||||
private getCORSProxyPath(): string {
|
||||
//TODO: this path should be passed in as a variable
|
||||
const basePath = globalThis.location.pathname.split('/web').slice(0, 1)[0];
|
||||
|
||||
return `${globalThis.location.origin}${basePath || '/'}cors/`
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,15 @@ import {Source} from '../../../models/database/source';
|
|||
import {IDatabaseRepository} from '../../../database/interface';
|
||||
import {ResourceFhir} from '../../../models/database/resource_fhir';
|
||||
import {UpsertSummary} from '../../../models/fasten/upsert-summary';
|
||||
import {ClientConfig} from '../../../models/client/client-config';
|
||||
|
||||
export class FHIR401Client extends BaseClient implements IClient {
|
||||
|
||||
//clients extending this class must validate fhirVersion matches using conformance/metadata url.
|
||||
fhirVersion = "4.0.1"
|
||||
|
||||
constructor(source: Source) {
|
||||
super(source);
|
||||
constructor(source: Source, clientConfig: ClientConfig) {
|
||||
super(source, clientConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,10 +3,11 @@ import {FHIR401Client} from './base/fhir401_r4_client';
|
|||
import {Source} from '../../models/database/source';
|
||||
import {IDatabaseRepository} from '../../database/interface';
|
||||
import {UpsertSummary} from '../../models/fasten/upsert-summary';
|
||||
import {ClientConfig} from '../../models/client/client-config';
|
||||
|
||||
export class BlueButtonClient extends FHIR401Client implements IClient {
|
||||
constructor(source: Source) {
|
||||
super(source);
|
||||
constructor(source: Source, clientConfig: ClientConfig) {
|
||||
super(source, clientConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import {IClient} from '../interface';
|
||||
import {FHIR401Client} from './base/fhir401_r4_client';
|
||||
import {Source} from '../../models/database/source';
|
||||
import {ClientConfig} from '../../models/client/client-config';
|
||||
|
||||
export class CareEvolutionClient extends FHIR401Client implements IClient {
|
||||
constructor(source: Source) {
|
||||
super(source);
|
||||
constructor(source: Source, clientConfig: ClientConfig) {
|
||||
super(source, clientConfig);
|
||||
//CareEvolution API requires the following Accept header for every request
|
||||
this.headers.set("Accept","application/json+fhir")
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@ import {FHIR401Client} from './base/fhir401_r4_client';
|
|||
import {Source} from '../../models/database/source';
|
||||
import {IDatabaseRepository} from '../../database/interface';
|
||||
import {UpsertSummary} from '../../models/fasten/upsert-summary';
|
||||
import {ClientConfig} from '../../models/client/client-config';
|
||||
|
||||
export class CernerClient extends FHIR401Client implements IClient {
|
||||
constructor(source: Source) {
|
||||
super(source);
|
||||
constructor(source: Source, clientConfig: ClientConfig) {
|
||||
super(source, clientConfig);
|
||||
//Cerner API requires the following Accept header for every request
|
||||
this.headers.set("Accept","application/json+fhir")
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import {IClient} from '../interface';
|
||||
import {FHIR401Client} from './base/fhir401_r4_client';
|
||||
import {Source} from '../../models/database/source';
|
||||
import {ClientConfig} from '../../models/client/client-config';
|
||||
|
||||
export class CignaClient extends FHIR401Client implements IClient {
|
||||
constructor(source: Source) {
|
||||
super(source);
|
||||
constructor(source: Source, clientConfig: ClientConfig) {
|
||||
super(source, clientConfig);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@ import {FHIR401Client} from './base/fhir401_r4_client';
|
|||
import {Source} from '../../models/database/source';
|
||||
import {IDatabaseRepository} from '../../database/interface';
|
||||
import {UpsertSummary} from '../../models/fasten/upsert-summary';
|
||||
import {ClientConfig} from '../../models/client/client-config';
|
||||
|
||||
export class EpicClient extends FHIR401Client implements IClient {
|
||||
constructor(source: Source) {
|
||||
super(source);
|
||||
constructor(source: Source, clientConfig: ClientConfig) {
|
||||
super(source, clientConfig);
|
||||
//Epic API requires the following Accept header for every request
|
||||
this.headers.set("Accept","application/json+fhir")
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@ import {FHIR401Client} from './base/fhir401_r4_client';
|
|||
import {Source} from '../../models/database/source';
|
||||
import {IDatabaseRepository} from '../../database/interface';
|
||||
import {UpsertSummary} from '../../models/fasten/upsert-summary';
|
||||
import {ClientConfig} from '../../models/client/client-config';
|
||||
|
||||
export class HealthITClient extends FHIR401Client implements IClient {
|
||||
constructor(source: Source) {
|
||||
super(source);
|
||||
constructor(source: Source, clientConfig: ClientConfig) {
|
||||
super(source, clientConfig);
|
||||
//HealthIT API requires the following Accept header for every request
|
||||
this.headers.set("Accept","application/json+fhir")
|
||||
}
|
||||
|
|
|
@ -2,9 +2,10 @@ import {IClient} from '../interface';
|
|||
import {FHIR401Client} from './base/fhir401_r4_client';
|
||||
import {Source} from '../../models/database/source';
|
||||
import {IDatabaseRepository} from '../../database/interface';
|
||||
import {ClientConfig} from '../../models/client/client-config';
|
||||
|
||||
export class LogicaClient extends FHIR401Client implements IClient {
|
||||
constructor(source: Source) {
|
||||
super(source);
|
||||
constructor(source: Source, clientConfig: ClientConfig) {
|
||||
super(source, clientConfig);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,4 @@ export interface IDatabaseRepository {
|
|||
GetResource(resource_id: string): Promise<ResourceFhir>
|
||||
GetResources(): Promise<IDatabasePaginatedResponse>
|
||||
GetResourcesForSource(source_id: string, source_resource_type?: string): Promise<IDatabasePaginatedResponse>
|
||||
|
||||
GetEndpointAbsolutePath(currentUrl: {pathname: string, protocol: string, host: string}, relativePath: string): string
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import {DocType} from './constants';
|
|||
import {ResourceFhir} from '../models/database/resource_fhir';
|
||||
import {ResourceTypeCounts, SourceSummary} from '../models/fasten/source-summary';
|
||||
import {Base64} from '../utils/base64';
|
||||
import {GetEndpointAbsolutePath} from '../utils/endpoint_absolute_path';
|
||||
|
||||
// PouchDB & plugins
|
||||
import * as PouchDB from 'pouchdb/dist/pouchdb';
|
||||
|
@ -18,6 +19,7 @@ import {PouchdbUpsert} from './plugins/upsert';
|
|||
import {UpsertSummary} from '../models/fasten/upsert-summary';
|
||||
|
||||
import {PouchdbCryptConfig, PouchdbCrypto, PouchdbCryptoOptions} from './plugins/crypto';
|
||||
import {utils} from 'protractor';
|
||||
|
||||
// !!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!
|
||||
// most pouchdb plugins seem to fail when used in a webworker.
|
||||
|
@ -80,7 +82,7 @@ export class PouchdbRepository implements IDatabaseRepository {
|
|||
this.remotePouchEndpoint = couchDbEndpointBase
|
||||
} else {
|
||||
//relative, we need to retrive the absolutePath from base
|
||||
this.remotePouchEndpoint = this.GetEndpointAbsolutePath(globalThis.location, couchDbEndpointBase)
|
||||
this.remotePouchEndpoint = GetEndpointAbsolutePath(globalThis.location, couchDbEndpointBase)
|
||||
}
|
||||
|
||||
//setup PouchDB Plugins
|
||||
|
@ -446,25 +448,4 @@ export class PouchdbRepository implements IDatabaseRepository {
|
|||
}
|
||||
return h
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Helper methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//Fasten may be served behind a reverse proxy with a subpath, so lets try to find that component if it exists.
|
||||
// if no subpath is found, just use the current url information to generate a path
|
||||
public GetEndpointAbsolutePath(currentUrl: {pathname: string, protocol: string, host: string}, relativePath: string): string {
|
||||
//no `/web` path to strip out, lets just use the relative path
|
||||
let absolutePath = relativePath
|
||||
|
||||
if(currentUrl.pathname.includes('/web')){
|
||||
// probably running locally, and *may* include a subpath
|
||||
let subPath = currentUrl.pathname.split('/web').slice(0, 1)[0]
|
||||
if(subPath != "/"){
|
||||
//subpath, so we need to update the absolutePath with the subpath before adding the relative path to the end
|
||||
absolutePath = subPath + relativePath
|
||||
}
|
||||
}
|
||||
return `${currentUrl.protocol}//${currentUrl.host}${absolutePath}`
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import {LighthouseSourceMetadata} from '../lighthouse/lighthouse-source-metadata';
|
||||
import {SourceType} from '../database/source_types';
|
||||
|
||||
export class ClientConfig {
|
||||
fasten_api_endpoint_base: string
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Helper methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//Fasten may be served behind a reverse proxy with a subpath, so lets try to find that component if it exists.
|
||||
// if no subpath is found, just use the current url information to generate a path
|
||||
export function GetEndpointAbsolutePath(currentUrl: {pathname: string, protocol: string, host: string}, relativePath: string): string {
|
||||
//no `/web` path to strip out, lets just use the relative path
|
||||
let absolutePath = relativePath
|
||||
|
||||
if(currentUrl.pathname.includes('/web')){
|
||||
// probably running locally, and *may* include a subpath
|
||||
let subPath = currentUrl.pathname.split('/web').slice(0, 1)[0]
|
||||
if(subPath != "/"){
|
||||
//subpath, so we need to update the absolutePath with the subpath before adding the relative path to the end
|
||||
absolutePath = subPath + relativePath
|
||||
}
|
||||
}
|
||||
return `${currentUrl.protocol}//${currentUrl.host}${absolutePath}`
|
||||
}
|
Loading…
Reference in New Issue