829 lines
14 KiB
JavaScript
829 lines
14 KiB
JavaScript
/*
|
|
|
|
Copyright (c) 2020, 2023, The Unified Company.
|
|
|
|
This code is part of Unify.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the ESA Software Community License - Strong Copyleft LICENSE,
|
|
as published by the ESA.
|
|
See the ESA Software Community License - Strong Copyleft LICENSE, for more details.
|
|
|
|
https://unifyjs.org
|
|
|
|
*/
|
|
|
|
|
|
import fs from 'fs';
|
|
|
|
import path from 'path';
|
|
|
|
import { spawn } from 'child_process';
|
|
|
|
import filemanager from './filemanager.js';
|
|
|
|
import unify from '../unify/unify.js';
|
|
|
|
import tools from '../unify/tools.js';
|
|
|
|
import colors from '../unify/consoleColors.js';
|
|
|
|
import groupsFlat from './themeGroups.js';
|
|
|
|
import cacheManager from "./scripts/cacheManager.js";
|
|
|
|
import { gpp } from '../node_modules/node-gpp/child.js';
|
|
|
|
import simplePath from '../unify/simplePath.js';
|
|
|
|
|
|
|
|
export default class hotSwap{
|
|
|
|
|
|
allPlatformFiles = new Array();
|
|
|
|
cache = new cacheManager();
|
|
|
|
gpp = new gpp();
|
|
|
|
|
|
constructor( clients ) {
|
|
|
|
this.clients = clients;
|
|
|
|
this.create();
|
|
|
|
this.createPlatformCachePath();
|
|
|
|
this.createGlobals();
|
|
|
|
}
|
|
|
|
createGlobals() {
|
|
|
|
if( !global.visibleElements ) {
|
|
|
|
global.visibleElements = new Array();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
createPlatformCachePath() {
|
|
|
|
this.pathToPlatforms = new simplePath();
|
|
|
|
this.pathToPlatforms.beginWithSlash = false;
|
|
|
|
this.pathToPlatforms.endWithSlash = true;
|
|
|
|
this.pathToPlatforms.add( "framework" )
|
|
|
|
this.pathToPlatforms.add( "cache" )
|
|
|
|
this.pathToPlatforms.add( "platforms" )
|
|
|
|
}
|
|
|
|
setSocketManager( socketManager ) {
|
|
|
|
this.socketManager = socketManager;
|
|
|
|
}
|
|
|
|
createInheritenceCache() {
|
|
|
|
}
|
|
|
|
async spawnNodemonInstance() {
|
|
|
|
|
|
var files = new filemanager( "./application/" );
|
|
|
|
await files.findApplicationFiles( "./application");
|
|
|
|
|
|
var directories = files.directories;
|
|
|
|
var that = this;
|
|
|
|
for (var i = 0; i < directories.length; i++) {
|
|
|
|
var directory = directories[ i ];
|
|
|
|
var pathToFile = new simplePath();
|
|
|
|
pathToFile.beginWithSlash = false;
|
|
|
|
pathToFile.endWithSlash = true;
|
|
|
|
pathToFile.add( "application" )
|
|
|
|
pathToFile.add( directory )
|
|
|
|
|
|
let directoryPath = path.resolve( pathToFile.resolve() );
|
|
|
|
//console.log("Watch directory:", i, colors.green( directoryPath ) );
|
|
|
|
|
|
var callback = function( eventType, filename ) {
|
|
|
|
var filePath = directoryPath + "/" + filename;
|
|
|
|
console.log("file changed ", eventType, filePath );
|
|
|
|
that.message( eventType, filePath );
|
|
|
|
};
|
|
|
|
if ( fs.existsSync( directoryPath ) ) {
|
|
|
|
fs.watch( directoryPath, callback )
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
spawnNodemon() {
|
|
|
|
this.createInheritenceCache();
|
|
|
|
try {
|
|
|
|
this.spawnNodemonInstance();
|
|
|
|
} catch ( error ) {
|
|
|
|
//console.error("Nodemon Crashed, Instantiating a new instance of nodemon..", error);
|
|
|
|
this.spawnNodemonInstance();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
create() {
|
|
|
|
//if( global.clusterID == 1 ) {
|
|
|
|
var app = this.spawnNodemon();
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
async message( event, file ) {
|
|
|
|
if( event == "change" ) {
|
|
|
|
//var files = event.data;
|
|
|
|
this.updateFiles( file );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
getPlatformCachePath() {
|
|
|
|
var cachePath = new simplePath();
|
|
|
|
cachePath.beginWithSlash = false;
|
|
|
|
cachePath.add( "framework" );
|
|
|
|
cachePath.add( "cache" );
|
|
|
|
cachePath.add( "platforms" );
|
|
|
|
cachePath.add( global.os );
|
|
|
|
cachePath.add( global.device );
|
|
|
|
cachePath.add( global.tint );
|
|
|
|
|
|
return cachePath.resolve();
|
|
|
|
}
|
|
|
|
getPathParts( file ) {
|
|
|
|
var rootDir = tools.slash( path.resolve("./") ).replace("C:/", "c:/");
|
|
|
|
var fullPath = file.replace( rootDir, "" );
|
|
|
|
var pathParts = fullPath.split("/");
|
|
|
|
return pathParts;
|
|
|
|
}
|
|
|
|
async processSource( fileObject, filePath ) {
|
|
|
|
var clientFiles = new filemanager();
|
|
|
|
clientFiles.cache_directory = this.getPlatformCachePath();
|
|
|
|
clientFiles.addCustomReplacements();
|
|
|
|
await clientFiles.processSource( fileObject, filePath, fileObject.depth - 2 )
|
|
|
|
}
|
|
|
|
getRelativePath( pathParts ) {
|
|
|
|
var relativeApplicationPath = pathParts.join("/").replace("/application/", "");
|
|
|
|
return tools.slash( relativeApplicationPath );
|
|
|
|
}
|
|
|
|
async createFileObject( filePath ) {
|
|
|
|
var slashedFilePath = tools.slash( filePath );
|
|
|
|
var pathParts = this.getPathParts( slashedFilePath );
|
|
|
|
|
|
var fileObject = new Object();
|
|
|
|
fileObject.name = pathParts.pop();
|
|
|
|
fileObject.depth = pathParts.length;
|
|
|
|
fileObject.path = this.getRelativePath( pathParts );
|
|
|
|
fileObject.type = "file";
|
|
|
|
fileObject.files = new Array();
|
|
|
|
|
|
await this.processSource( fileObject, slashedFilePath );
|
|
|
|
|
|
return fileObject;
|
|
|
|
}
|
|
|
|
updateClientObjects( newInstance, clientObject ) {
|
|
|
|
//console.log( "nodeMethods", clientObject );
|
|
|
|
var nodeMethods = newInstance.__nodeMethods.split(",");
|
|
|
|
|
|
|
|
for ( var j = 0; j < nodeMethods.length; j++ ) {
|
|
|
|
var nodeMethodName = nodeMethods[j];
|
|
|
|
clientObject[ nodeMethodName ] = newInstance[nodeMethodName];
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
updateMethodByClient( newInstance, client, className ) {
|
|
|
|
var classObjects = client.classObjects;
|
|
|
|
var clientObject = classObjects[ className ];
|
|
|
|
|
|
if( clientObject ) {
|
|
|
|
this.updateClientObjects( newInstance, clientObject );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
updateClients( newInstance, clients, className ) {
|
|
|
|
//for ( var i = 0; i < clients.length; i++ ) {
|
|
|
|
for ( const [ key, client ] of Object.entries( clients ) ) {
|
|
|
|
//var client = clients[ i ];
|
|
|
|
this.updateMethodByClient( newInstance, client, className );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
async updateMethods( newInstance, clients ) {
|
|
|
|
var className = newInstance.getClassName();
|
|
|
|
if( global.mode == "development") {
|
|
|
|
this.updateClients( newInstance, clients, className );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
getAllExtendedObjects( extendObjects, pathsArray ) {
|
|
|
|
//console.log("extendObjects", extendObjects, pathsArray);
|
|
|
|
for ( var c = 0; c < extendObjects.length - 1; c++ ) {
|
|
|
|
var objectName = extendObjects[c];
|
|
|
|
var extendedObject = global.classObjects[ objectName ]
|
|
|
|
if( extendedObject ) {
|
|
|
|
pathsArray.push( extendedObject.__sourcePath );
|
|
|
|
} else {
|
|
|
|
console.error( "Class not found in core.classObjects.", objectName );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
getExtendedDependencyPathsOfObject( object, pathsArray ) {
|
|
|
|
//var visible = global.visibleElements.includes( object.getClassName() );
|
|
|
|
//if( visible ) {
|
|
|
|
pathsArray.push( object.__sourcePath );
|
|
|
|
var extendObjects = object.getExtends();
|
|
|
|
extendObjects = tools.removeDuplicates( extendObjects );
|
|
|
|
this.getAllExtendedObjects( extendObjects, pathsArray );
|
|
|
|
//console.log("extendObjects", extendObjects);
|
|
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
getExtendedDependencyPaths( objects ) {
|
|
|
|
var pathsArray = new Array();
|
|
|
|
for ( var i = 0; i < objects.length; i++ ) {
|
|
|
|
var object = objects[i];
|
|
|
|
//console.log("getExtendedDependencyPaths", object.__sourcePath );
|
|
|
|
this.getExtendedDependencyPathsOfObject( object, pathsArray );
|
|
|
|
}
|
|
|
|
pathsArray = tools.removeDuplicates( pathsArray );
|
|
|
|
return pathsArray;
|
|
|
|
}
|
|
|
|
reloadPathCache( paths, group ) {
|
|
|
|
for ( var c = 0; c < paths.length; c++ ) {
|
|
|
|
var cachePath = this.pathToPlatforms.clone();
|
|
|
|
cachePath.beginWithSlash = true;
|
|
|
|
cachePath.add( "Original" );
|
|
|
|
cachePath.add( group.path );
|
|
|
|
cachePath.add( paths[ c ] );
|
|
|
|
this.allPlatformFiles.push( cachePath.resolve() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
async reloadAllThemeCache( groups, paths ) {
|
|
|
|
for ( var i = 0; i < groups.length; i++ ) {
|
|
|
|
var group = groups[i];
|
|
|
|
this.reloadPathCache( paths, group );
|
|
|
|
await this.renewPlatform( group.name, group.path, paths );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
createApplicationPath( path, filename ) {
|
|
|
|
var fullPath = this.pathToPlatforms.clone();
|
|
|
|
fullPath.absolute = true;
|
|
|
|
fullPath.add( global.os )
|
|
|
|
fullPath.add( global.device )
|
|
|
|
fullPath.add( global.tint )
|
|
|
|
fullPath.add( path )
|
|
|
|
fullPath.add( filename + "?disableCache=" + Math.random() )
|
|
|
|
|
|
return fullPath.resolve();
|
|
}
|
|
|
|
async processDependencies( fileObject, groupsFlatSelection ) {
|
|
|
|
var path = this.createApplicationPath( fileObject.path, fileObject.name );
|
|
|
|
var importPromise = import( "file://" + path );
|
|
|
|
var that = this;
|
|
|
|
importPromise.catch( error => {
|
|
|
|
console.log("Error loading dynamic import. Your code contains an error.", error)
|
|
|
|
} ).then( async function( module ) {
|
|
|
|
if( !module ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
var newInstance = new module.default();
|
|
|
|
await that.updateInstance( newInstance, groupsFlatSelection );
|
|
|
|
});
|
|
|
|
}
|
|
|
|
async prepareInstance( newInstance ) {
|
|
|
|
if( !newInstance ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
unify.extend( newInstance );
|
|
|
|
if( !newInstance.getClassName ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
await this.updateMethods( newInstance, this.clients );
|
|
|
|
return newInstance;
|
|
|
|
}
|
|
|
|
getDependencieObjects( newInstance ) {
|
|
|
|
var className = newInstance.getClassName();
|
|
|
|
//console.log("dependencieMap", className, Object.keys( global.dependencieMap ) ) ;
|
|
|
|
var dependencyObjects = global.dependencieMap[ className ];
|
|
|
|
if( dependencyObjects ) {
|
|
|
|
return dependencyObjects;
|
|
|
|
} else {
|
|
|
|
return new Array();
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
async updateInstance( newInstance, groupsFlatSelection ) {
|
|
|
|
var newInstance = await this.prepareInstance( newInstance );
|
|
|
|
if( !newInstance ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
var dependencyObjects = this.getDependencieObjects( newInstance )
|
|
|
|
var pathsArray = this.getExtendedDependencyPaths( dependencyObjects );
|
|
|
|
await this.reloadAllThemeCache( groupsFlatSelection, pathsArray )
|
|
|
|
}
|
|
|
|
getAbsolutePathByFile( file, customPath ) {
|
|
|
|
var absolutePath = this.pathToPlatforms.clone();
|
|
|
|
absolutePath.beginWithSlash = true;
|
|
|
|
absolutePath.add( "Original" );
|
|
|
|
if( customPath ) {
|
|
|
|
absolutePath.add( customPath );
|
|
|
|
} else {
|
|
|
|
absolutePath.add( "Server" );
|
|
|
|
}
|
|
|
|
|
|
|
|
absolutePath.add( file.path );
|
|
|
|
absolutePath.add( file.name );
|
|
|
|
return absolutePath.resolve();
|
|
|
|
}
|
|
|
|
addPlatformPaths( files, customPath = false ) {
|
|
|
|
for ( var i = 0; i < files.length; i++ ) {
|
|
|
|
var file = files[i];
|
|
|
|
var absolutePath = this.getAbsolutePathByFile( file, customPath );
|
|
|
|
if( file.type == "file" ) {
|
|
|
|
this.allPlatformFiles.push( absolutePath );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
async processServerFiles( filesArray ) {
|
|
|
|
var cachePath = tools.slash( "framework/cache/platforms/Original/Server/" );
|
|
|
|
var server_files = new filemanager( cachePath );
|
|
|
|
server_files.definePragma("SERVER");
|
|
|
|
server_files.definePragma("server_cache");
|
|
|
|
server_files.addCustomReplacements();
|
|
|
|
server_files.files = filesArray;
|
|
|
|
this.addPlatformPaths( filesArray );
|
|
|
|
await server_files.writeFiles();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
async updateConfig() {
|
|
|
|
var cachePath = tools.slash( "framework/server_cache/" );
|
|
|
|
var server_files = new filemanager( cachePath );
|
|
|
|
await server_files.findApplicationFiles( "./application");
|
|
|
|
var applications = server_files.applications;
|
|
|
|
var application = await this.cache.importApplication( applications[0].path );
|
|
|
|
|
|
this.cache.getApplicationProperties( application )
|
|
|
|
await this.cache.writeApplicationPropertiesToFile();
|
|
|
|
}
|
|
|
|
createGroupPath() {
|
|
|
|
var groupPath = new simplePath();
|
|
|
|
groupPath.endWithSlash = false;
|
|
|
|
|
|
groupPath.add( global.os )
|
|
|
|
groupPath.add( global.device )
|
|
|
|
groupPath.add( global.tint )
|
|
|
|
return groupPath.resolve();
|
|
|
|
}
|
|
|
|
createGroup() {
|
|
|
|
var groups = new Array( groupsFlat[5] );
|
|
|
|
//group.path = this.createGroupPath();
|
|
|
|
groups[0].path = this.createGroupPath();
|
|
|
|
return groups;
|
|
|
|
}
|
|
|
|
async processThemeGroups( groups, filesArray ) {
|
|
|
|
for ( var i = 0; i < groups.length; i++ ) {
|
|
|
|
var group = groups[i];
|
|
|
|
await this.processPlatform( group.name, group.path, filesArray );//filesArray );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
async writeCachePathsToJSON() {
|
|
|
|
var jsonFiles = JSON.stringify( this.allPlatformFiles );
|
|
|
|
var path = tools.slash("framework/cache/platforms/files.json");
|
|
|
|
await fs.writeFileSync( path, jsonFiles, "utf8" );
|
|
|
|
}
|
|
|
|
async updateFile( file ) {
|
|
|
|
var fileObject = await this.createFileObject( file ) ;
|
|
|
|
var themeGroups = this.createGroup();
|
|
|
|
var filesArray = new Array( fileObject );
|
|
|
|
|
|
await this.processThemeGroups( themeGroups, filesArray );
|
|
|
|
await this.processServerFiles( filesArray );
|
|
|
|
await this.updateConfig();
|
|
|
|
await this.writeCachePathsToJSON();
|
|
|
|
await this.gpp.convert_files();
|
|
|
|
//console.log("themeGroups", themeGroups);
|
|
|
|
await this.processDependencies( fileObject, themeGroups );
|
|
|
|
console.log( colors.green( "Updated file:" ), colors.green( file ) );
|
|
|
|
this.sendFileToClient( fileObject );
|
|
|
|
}
|
|
|
|
async updateFiles( file ) {
|
|
|
|
//for (var i = 0; i < files.length; i++) {
|
|
|
|
// var file = files[i];
|
|
|
|
await this.updateFile( file );
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
sendFileToClient( fileObject ) {
|
|
|
|
var clients = this.clients;
|
|
|
|
var parameters = new Object();
|
|
|
|
parameters.file = fileObject;
|
|
|
|
parameters.action = "updateFile";
|
|
|
|
console.log( "send updated file to client", clients.length );
|
|
|
|
for ( const [ key, client ] of Object.entries( clients ) ) {
|
|
|
|
|
|
|
|
client.debugMessage( parameters )
|
|
|
|
}
|
|
|
|
}
|
|
|
|
reloadPathCache( paths, group ) {
|
|
|
|
for ( var c = 0; c < paths.length; c++ ) {
|
|
|
|
var cachePath = this.pathToPlatforms.clone();
|
|
|
|
cachePath.beginWithSlash = true;
|
|
|
|
cachePath.add( "Original" );
|
|
|
|
cachePath.add( group.path );
|
|
|
|
cachePath.add( paths[ c ] );
|
|
|
|
this.allPlatformFiles.push( cachePath.resolve() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
definePragmas( files, path ) {
|
|
|
|
var terms = path.split("/");
|
|
|
|
terms.shift();
|
|
|
|
for ( var i = 0; i < terms.length; i++ ) {
|
|
|
|
files.definePragma( terms[i] );
|
|
|
|
}
|
|
|
|
files.definePragma("CLIENT");
|
|
|
|
}
|
|
|
|
getThemePath( path, isOriginal = false ) {
|
|
|
|
var fullPath = this.pathToPlatforms.clone();
|
|
|
|
if( isOriginal ) {
|
|
|
|
fullPath.add( "Original" );
|
|
|
|
}
|
|
|
|
fullPath.add( path );
|
|
|
|
return fullPath.resolve();
|
|
|
|
}
|
|
|
|
async processPlatform( name, path, filesArray ) {
|
|
|
|
var themePath = this.getThemePath( path );
|
|
|
|
var files = new filemanager( themePath );
|
|
|
|
files.addCustomReplacements();
|
|
|
|
this.definePragmas( files, path );
|
|
|
|
files.files = filesArray;
|
|
|
|
files.temporary_cache_directory = this.getThemePath( path, true );
|
|
|
|
await files.writeFiles("client");
|
|
|
|
this.addPlatformPaths( files.files, path )
|
|
|
|
}
|
|
|
|
async renewPlatform( name, path, filesArray ) {
|
|
|
|
var themePath = this.getThemePath( path, true );
|
|
|
|
//console.log("getThemePath", path);
|
|
|
|
var files = new filemanager( themePath );
|
|
|
|
await files.renewCache( path, filesArray );
|
|
|
|
}
|
|
|
|
}
|
|
|