import { PiLogger } from "@projectit/core" ; import { PiNamedElement } from "@projectit/core" ; import { GenericModelSerializer } from "@projectit/core" ; import { IServerCommunication } from "./IServerCommunication" ; import { setUserMessage } from "../webapp-ts-utils/UserMessageUtils" ; const LOGGER = new PiLogger ( "ServerCommunication" ) ; const modelUnitInterfacePostfix = "Public" ; const node_port = process . env . NODE_PORT || 3001 ; const SERVER_URL = `http://127.0.0.1:${ node_port }/` ; console . log ( "NODE_PORT:" + node_port + "  env " + JSON . stringify ( process . env ) ) ; export class ServerCommunication implements IServerCommunication { static serial : GenericModelSerializer = new GenericModelSerializer ( ) ; static instance : ServerCommunication ; static getInstance ( ) { if ( ! ( ! ! ServerCommunication . instance ) ) { ServerCommunication . instance = new ServerCommunication ( ) ; } return ServerCommunication . instance ; } private static findParams ( params ) { if ( ! ! params && params . length > 0 ) { return "?" + params ; } else { return "" ; } } param modelName param unitName param piUnit async putModelUnit ( modelName , unitName , piUnit ) { LOGGER . log ( `ServerCommunication.putModelUnit ${ modelName }/${ unitName }` ) ; if ( ! ! unitName && unitName . length > 0 && unitName . match ( /^[a-z,A-Z][a-z,A-Z0-9_\-]*$/ ) ) { const model = ServerCommunication . serial . convertToJSON ( piUnit ) ; const publicModel = ServerCommunication . serial . convertToJSON ( piUnit , true ) ; await this . putWithTimeout ( `putModelUnit` , model , `folder=${ modelName }&name=${ unitName }` ) ; await this . putWithTimeout ( `putModelUnit` , publicModel , `folder=${ modelName }&name=${ unitName }${ modelUnitInterfacePostfix }` ) ; } else { LOGGER . error ( this , "Name of Unit '" + unitName + "' may contain only characters, numbers, '_', or '-', and must start with a character." ) ; } } param modelName param unitName async deleteModelUnit ( modelName , unitName ) { LOGGER . log ( `ServerCommunication.deleteModelUnit ${ modelName }/${ unitName }` ) ; if ( ! ! unitName && unitName . length > 0 ) { await this . fetchWithTimeout < any > ( `deleteModelUnit` , `folder=${ modelName }&name=${ unitName }` ) ; await this . fetchWithTimeout < any > ( `deleteModelUnit` , `folder=${ modelName }&name=${ unitName }${ modelUnitInterfacePostfix }` ) ; } } param modelName async deleteModel ( modelName ) { LOGGER . log ( `ServerCommunication.deleteModel ${ modelName }` ) ; if ( ! ! modelName && modelName . length > 0 ) { await this . fetchWithTimeout < any > ( `deleteModel` , `folder=${ modelName }` ) ; } } param modelListCallback async loadModelList ( modelListCallback ) { LOGGER . log ( `ServerCommunication.loadModelList` ) ; const res = await this . fetchWithTimeout < string [ ] > ( `getModelList` ) ; if ( ! ! res ) { modelListCallback ( res ) ; } else { modelListCallback ( [ ] ) ; } } param modelName param modelListCallback async loadUnitList ( modelName , modelListCallback ) { LOGGER . log ( `ServerCommunication.loadUnitList` ) ; let modelUnits = await this . fetchWithTimeout < string [ ] > ( `getUnitList` , `folder=${ modelName }` ) ; if ( ! ! modelUnits ) { modelUnits = modelUnits . filter ( ( name ) => name . indexOf ( modelUnitInterfacePostfix ) === - 1 ) ; modelListCallback ( modelUnits ) ; } else { modelListCallback ( [ ] ) ; } } param modelName param unitName param loadCallback async loadModelUnit ( modelName , unitName , loadCallback ) { LOGGER . log ( `ServerCommunication.loadModelUnit ${ unitName }` ) ; if ( ! ! unitName && unitName . length > 0 ) { const res = await this . fetchWithTimeout < Object > ( `getModelUnit` , `folder=${ modelName }&name=${ unitName }` ) ; if ( ! ! res ) { try { const unit = ServerCommunication . serial . toTypeScriptInstance ( res ) ; loadCallback ( unit ) ; } catch ( e ) { LOGGER . error ( this , "loadModelUnit, " + e . message ) ; setUserMessage ( e . message ) ; } } } } param modelName param unitName param loadCallback async loadModelUnitInterface ( modelName , unitName , loadCallback ) { LOGGER . log ( `ServerCommunication.loadModelUnitInterface for ${ modelName }/${ unitName }` ) ; if ( ! ! unitName && unitName . length > 0 ) { const res = await this . fetchWithTimeout < Object > ( `getModelUnit` , `folder=${ modelName }&name=${ unitName }${ modelUnitInterfacePostfix }` ) ; if ( ! ! res ) { try { const model = ServerCommunication . serial . toTypeScriptInstance ( res ) ; loadCallback ( model ) ; } catch ( e ) { LOGGER . error ( this , "loadModelUnitInterface, " + e . message ) ; setUserMessage ( e . message ) ; } } } } private async fetchWithTimeout < T > ( method , params ? ) { params = ServerCommunication . findParams ( params ) ; try { const controller = new AbortController ( ) ; const timeoutId = setTimeout ( ( ) => controller . abort ( ) , 2000 ) ; const promise = await fetch ( `${ SERVER_URL }${ method }${ params }` , { signal : controller . signal , method : "get" , headers : { "Content-Type" : "application/json" } } ) ; clearTimeout ( timeoutId ) ; return await promise . json ( ) ; } catch ( e ) { this . handleError ( e ) ; } return null ; } private async putWithTimeout ( method , data , params ? ) { params = ServerCommunication . findParams ( params ) ; try { const controller = new AbortController ( ) ; const timeoutId = setTimeout ( ( ) => controller . abort ( ) , 2000 ) ; await fetch ( `${ SERVER_URL }${ method }${ params }` , { signal : controller . signal , method : "put" , headers : { "Content-Type" : "application/json" } , body : JSON . stringify ( data ) } ) ; clearTimeout ( timeoutId ) ; } catch ( e ) { this . handleError ( e ) ; } } private handleError ( e ) { let errorMess = e . message ; if ( e . message . includes ( "aborted" ) ) { errorMess = `Time out: no response from ${ SERVER_URL }.` ; } LOGGER . error ( this , errorMess ) ; setUserMessage ( errorMess ) ; } }