Commit ce95aebf authored by Leon Müller's avatar Leon Müller
Browse files

Improved file system performance, improved auto commit feature, added help windows

parent 68a7401c
......@@ -15,8 +15,8 @@ dist/
mount/
#local jsons
.src/config.json
.src/LocalChangeManager/uncommitedChanges.json
src/config.json
src/LocalChangeManager/uncommitedChanges.json
......@@ -16,7 +16,7 @@ export class File {
this.resourceID = path.replace(pat.extname(path),"")
this.extension = extension;
this.store = store;
this.mtime = mtime;
this.mtime = new Date(mtime);
this.mode = mode
this.lastUpdated = Date.now();
......
......@@ -18,6 +18,7 @@ const mime = require('mime-types')
const rdfExtension = config.rdfExtension;
import {File} from './File';
import { IResourceID } from "@i5/factlib.js/src/datamodels/interfaces/IResourceID";
import { read } from "fs";
var fd = 42;
async function listContent(uri:string) {
......@@ -53,7 +54,12 @@ async function listResources(dir:Directory) {
}
else if(binaryFiles.map((x:any)=>x.replace(pat.extname(x),"")).includes(resourceID.resourceID)) {
const cachedFile = fileCache[fileCache.map((x:any)=>(x.path).replace(pat.extname(x.path),"")).indexOf(resourceID.resourceID)]
return resourceID.resourceName+cachedFile.extension;
if(cachedFile) {
return resourceID.resourceName+cachedFile.extension;
}
else {
return resourceID.resourceName;
}
}
else if(!files.includes(resourceID.resourceID+rdfExtension) && !binaryFiles.map((x:any)=>x.replace(pat.extname(x),"")).includes(resourceID.resourceID)) {
createNonBinaryFile(resourceID);
......@@ -132,25 +138,25 @@ async function createBinaryFile(resourceID:IResourceID) {
async function updateFile(path:string) {
const resourceID = idFactory.parseURIToResourceID(pat.join(root,path.replace(pat.extname(path),"")))
const exists = await service.isResourceExistent(resourceID);
if(exists) {
if(exists && !deletedResources.includes(path)) {
const resource = await service.getLastFactRevision(resourceID);
const mtime = new Date(resource.factID.revisionID)
const cachedFile = fileCache[fileCache.map((x:any)=>x.path).indexOf(path)]
if(mtime < cachedFile.mtime && !tempFiles.includes(path) && !tempBinaryFiles.includes(path) && !deletedResources.includes(path)) { // update a file TODO!!!!!!!!!!!!!!!!!!! UPDATE BINARIES
console.log("update " + path)
cachedFile.mtime = mtime;
cachedFile.store = resource.serialize();
cachedFile.lastUpdated = Date.now()
//console.log(path + ": " + mtime + " | " + cachedFile.mtime)
if(mtime > cachedFile.mtime && !tempFiles.includes(path) && !tempBinaryFiles.includes(path) && !deletedResources.includes(path)) { // update a file TODO!!!!!!!!!!!!!!!!!!! UPDATE BINARIES
console.log("update " + path)
cachedFile.mtime = mtime;
cachedFile.store = resource.serialize();
cachedFile.lastUpdated = Date.now();
fs.readFile(config.mountpoint + path, (err:any, data:any) => {
if (err) throw err;
});
updateChangeManager();
ops.chmod(path,33188,function(){});
updateChangeManager();
}
else if(mtime >= cachedFile.mtime && (tempFiles.includes(path))){ // server caught up with local change
console.log("CAUGHT NEW VERSION")
tempFiles.splice(tempFiles.indexOf(path),1)
updateChangeManager();
console.log("CAUGHT NEW VERSION")
tempFiles.splice(tempFiles.indexOf(path),1)
updateChangeManager();
}
else if(mtime >= cachedFile.mtime && (tempBinaryFiles.includes(path))) { // server caught up with local change
console.log("CAUGHT NEW VERSION")
......@@ -160,6 +166,7 @@ async function updateFile(path:string) {
}
else {
if(deletedResources.includes(path)) {
console.log("removed deleted")
deletedResources.splice(deletedResources.indexOf(path,1))
updateChangeManager();
}
......@@ -188,8 +195,10 @@ async function updateChangeManager() { //update the local change list
}
ChangeManager.deletedResources = deletedResources.map((x:any)=>x.replace(pat.extname(x),""));
if(autoCommitter.timerObj) {
autoCommitter.reset();
if(autoCommitter) {
if(autoCommitter.timerObj) {
autoCommitter.reset();
}
}
}
......@@ -458,17 +467,30 @@ export const ops = {
rename: async function(src:any, dest:any, cb:any) {
console.log("rename " + src + " | " + dest)
if(dest.includes(" ")) {
return process.nextTick(cb, Fuse.EROFS)
}
const cachedFile = fileCache[fileCache.map((x:any)=>x.path).indexOf(src)]
if(files.includes(src)) {
if(deletedResources.includes(dest)) {
deletedResources.splice(deletedResources.indexOf(dest),1)
if(!tempFiles.includes(dest)) {
tempFiles.push(dest);
}
deletedResources.push(src)
cachedFile.path = dest;
cachedFile.extension = pat.extname(dest);
cachedFile.mtime = new Date();
updateChangeManager();
return process.nextTick(cb, 0)
}
else {
tempFiles.push(dest)
if(!tempFiles.includes(dest)) {
tempFiles.push(dest);
}
cachedFile.path = dest;
cachedFile.extension = pat.extname(dest);
cachedFile.mtime = new Date();
deletedResources.push(src)
updateChangeManager();
return process.nextTick(cb, 0)
......@@ -477,13 +499,23 @@ export const ops = {
else if(binaryFiles.includes(src)) {
if(deletedResources.includes(dest)) {
deletedResources.splice(deletedResources.indexOf(dest),1)
deletedResources.push(src)
if(!tempBinaryFiles.includes(dest)) {
tempBinaryFiles.push(dest);
}
cachedFile.path = dest;
cachedFile.extension = pat.extname(dest);
cachedFile.mtime = new Date();
updateChangeManager();
return process.nextTick(cb, 0)
}
else {
tempBinaryFiles.push(dest)
if(!tempBinaryFiles.includes(dest)) {
tempBinaryFiles.push(dest);
}
cachedFile.path = dest;
cachedFile.extension = pat.extname(dest);
cachedFile.mtime = new Date();
deletedResources.push(src)
updateChangeManager();
return process.nextTick(cb, 0)
......@@ -492,14 +524,24 @@ export const ops = {
else if(tempFiles.includes(src)) {
if(deletedResources.includes(dest)) {
deletedResources.splice(deletedResources.indexOf(dest),1)
if(!tempFiles.includes(dest)) {
tempFiles.push(dest);
}
cachedFile.path = dest;
cachedFile.extension = pat.extname(dest);
cachedFile.mtime = new Date();
tempFiles.splice(tempFiles.indexOf(src),1)
updateChangeManager();
return process.nextTick(cb, 0)
}
else {
tempFiles[tempFiles.indexOf(src)] = dest
if(!tempFiles.includes(dest)) {
tempFiles.push(dest);
}
tempFiles.splice(tempFiles.indexOf(src),1)
cachedFile.path = dest
cachedFile.extension = pat.extname(dest);
cachedFile.mtime = new Date();
updateChangeManager();
return process.nextTick(cb, 0)
}
......@@ -507,14 +549,24 @@ export const ops = {
else if(tempBinaryFiles.includes(src)) {
if(deletedResources.includes(dest)) {
deletedResources.splice(deletedResources.indexOf(dest),1)
if(!tempBinaryFiles.includes(dest)) {
tempBinaryFiles.push(dest);
}
cachedFile.path = dest;
cachedFile.extension = pat.extname(dest);
cachedFile.mtime = new Date();
tempBinaryFiles.splice(tempBinaryFiles.indexOf(src),1)
updateChangeManager();
return process.nextTick(cb, 0)
}
else {
tempBinaryFiles[tempBinaryFiles.indexOf(src)] = dest
if(!tempBinaryFiles.includes(dest)) {
tempBinaryFiles.push(dest);
}
tempBinaryFiles.splice(tempBinaryFiles.indexOf(src),1)
cachedFile.path = dest
cachedFile.extension = pat.extname(dest);
cachedFile.mtime = new Date();
updateChangeManager();
return process.nextTick(cb, 0)
}
......@@ -586,7 +638,6 @@ export const ops = {
console.log("create Binary " + path)
tempBinaryFiles.push(path)
if(!fileCache.map((x:any)=>x.path).includes(path)) {
console.log(pat.extname(path))
fileCache.push(new File(path,"",undefined,undefined,pat.extname(path)));
}
///////////
......@@ -632,16 +683,20 @@ export const ops = {
}
setInterval(function() {
if((global as any).systemStatus == 1 && tempFiles.concat(tempBinaryFiles)/*.concat(deletedResources)*/.filter((y:any)=>!y.includes("/.")).length >0) {
for(const tempFile of tempFiles.concat(tempBinaryFiles)/*.concat(deletedResources)*/.filter((y:any)=>!y.includes("/."))) {
if(!tempFile.includes(" ")) {
console.log("go: " + tempFile)
updateFile(tempFile);
setInterval(function() {
if(autoCommitter) {
if(autoCommitter.timerObj) {
if((global as any).systemStatus == 1 && tempFiles.concat(tempBinaryFiles).concat(deletedResources).filter((y:any)=>!y.includes("/.")).length >0) {
for(const tempFile of tempFiles.concat(tempBinaryFiles).concat(deletedResources).filter((y:any)=>!y.includes("/."))) {
if(!tempFile.includes(" ") && !directories.includes(tempFile)) {
//console.log("go: " + tempFile)
updateFile(tempFile);
}
}
}
}
},500)
}
}
}
},500)
var autoCommitter:any;
(global as any).autoCommitter = autoCommitter;
......@@ -691,6 +746,9 @@ export class FactFUSE {
if (err) {
console.log('filesystem not unmounted', err)
} else {
if(autoCommitter) {
autoCommitter.stop();
}
console.log('filesystem unmounted')
cb();
}
......@@ -698,7 +756,12 @@ export class FactFUSE {
}
public startAutoCommitter() {
autoCommitter.start();
if(autoCommitter) {
autoCommitter.start();
}
else {
autoCommitter = new AutoCommitter(config.commitInterval);
}
}
public stopAutoCommitter() {
autoCommitter.stop();
......@@ -712,16 +775,17 @@ class AutoCommitter {
constructor(t:any) {
const self = this;
this.timerObj = setInterval(function () {
const arr = new Array(ChangeManager.tempFiles.length + ChangeManager.tempDirectories.length + ChangeManager.tempBinaryFiles.length+ ChangeManager.deletedResources.length).fill(1);
const numberOfChanges = ChangeManager.tempFiles.length + ChangeManager.tempBinaryFiles.length+ ChangeManager.deletedResources.length; // doesnt include directories. dirs only get pushed when they contain new resources
const arr = new Array(ChangeManager.tempFiles.length + ChangeManager.tempDirectories.length + ChangeManager.tempBinaryFiles.length+ ChangeManager.deletedResources.length).fill(1); //array indicating all changes are staged
const commit = new Commit("commit"+Date.now().toString(),"Automatic commit",arr);
//console.log(uncommittedChanges)
if(arr.length>0) {
if(numberOfChanges>0) {
//self.commitBlocked = true;
self.stop()
console.log(commit)
self.sendCommit(commit)
}
else if(arr.length==0) {
else if(numberOfChanges==0) {
(global as any).systemStatus = 1;
(global as any).tray.setIcon(new QIcon(pat.dirname(__dirname)+"/assets/logoMounted.png"));
(global as any).trayStatus.setEnabled(false);
......@@ -733,6 +797,7 @@ class AutoCommitter {
}
stop() {
if (this.timerObj) {
//console.log("stopped AutoCommit")
clearInterval(this.timerObj);
this.timerObj = null;
}
......@@ -741,18 +806,20 @@ class AutoCommitter {
start() {
if (!this.timerObj) {
//console.log("started AutoCommit")
const self = this;
this.stop();
this.timerObj = setInterval(function () {
const numberOfChanges = ChangeManager.tempFiles.length + ChangeManager.tempBinaryFiles.length+ ChangeManager.deletedResources.length; // doesnt include directories. dirs only get pushed when they contain new resources
const arr = new Array(ChangeManager.tempFiles.length + ChangeManager.tempDirectories.length + ChangeManager.tempBinaryFiles.length+ ChangeManager.deletedResources.length).fill(1);
const commit = new Commit("commit"+Date.now().toString(),"Automatic commit",arr);
if(arr.length>0) {
if(numberOfChanges>0) {
//self.commitBlocked = true;
self.stop();
console.log(commit)
self.sendCommit(commit)
}
else if(arr.length==0) {
else if(numberOfChanges==0) {
(global as any).systemStatus = 1;
(global as any).tray.setIcon(new QIcon(pat.dirname(__dirname)+"/assets/logoMounted.png"));
(global as any).trayStatus.setEnabled(false);
......@@ -765,6 +832,7 @@ class AutoCommitter {
}
reset() {
//console.log("reset AutoCommit")
return this.stop().start();
}
......
......@@ -81,7 +81,7 @@ export class CommitHandler {
candidate.addGeneratingActivity(pManager.activity)
const isFact = await service.isResourceExistent(candidate.resourceID);
if(isFact) {
await service.createBinaryFactRevision(candidate);
await service.createBinaryFactRevision(candidate);
}
else {
await service.createBinaryFactResource(candidate);
......
......@@ -55,8 +55,11 @@ export async function createBinaryResourceCandidate(path:string) {
return candidate;
}
else {
const fact = (await service.getLastFactRevision(resourceID))
const fact = (await service.getLastBinaryFactRevision(resourceID,""))
const candidate = fact.createCandidate()
//const c = service.getFactDagResourceFactory().create
//const candidate = service.getFactDagResourceFactory().createEmptyBinaryFactCandidate(resourceID, fs.createReadStream(mountpoint+path+extension), mime.lookup(extension));
//candidate.wasRevisionOf(fact);
candidate.attributeToAuthority(idFactory.createAuthorityResourceID(authorityID));
return candidate;
}
......
{
"Add": [
"/facts/bye s"
],
"Add": [],
"AddBin": [],
"AddDir": [],
"Remove": [
"/facts/byes"
]
"Remove": []
}
\ No newline at end of file
......@@ -3,7 +3,7 @@ import { CommitHandler } from '../LocalChangeManager/CommitHandler'
const config = require("../config.json")
//-------------------------------------------------------------------------------
const { QMainWindow,QIcon, QToolButton,QMenuBar,QScrollArea,QStatusBar,QPushButton, QLabel, QWidget, FlexLayout,QGridLayout,ButtonRole,QMessageBoxIcon, QBoxLayout,QLineEdit,QTextEdit,QGroupBox, QCheckBox,QFileDialog,FileMode,QListWidget,QListWidgetItem, QMessageBox } = require("@nodegui/nodegui");
const { QMainWindow,QIcon, QToolButton,QTableWidget,QTableWidgetItem,QMenuBar,QScrollArea,QStatusBar,QPushButton, QLabel, QWidget, FlexLayout,QGridLayout,ButtonRole,QMessageBoxIcon, QBoxLayout,QLineEdit,QTextEdit,QGroupBox, QCheckBox,QFileDialog,FileMode,QListWidget,QListWidgetItem, QMessageBox } = require("@nodegui/nodegui");
const mountpoint = config.mountpoint;
const root = config.ldpAddress;
const pat = require('path')
......@@ -39,6 +39,8 @@ export class CommitGUI {
usedList = new QListWidget();
generatedBox = new QGroupBox();
selectAllCheckBox = new QCheckBox();
helpButton = new QToolButton();
selectedFiles:any = [];
usedWidgets:any = [];
......@@ -49,17 +51,27 @@ export class CommitGUI {
constructor() {
this.win.setWindowTitle("Commit");
this.win.resize(400,300)
//this.rootLayout.setSpacing(0)
this.rootView.setObjectName("rootView");
this.rootView.setLayout(this.rootLayout);
this.topField.setLayout(this.topLayout);
this.midField.setLayout(this.midLayout);
this.addRemoveButtonField.setLayout(this.aRBFLayout);
this.rootLayout.addWidget(this.helpButton)
this.rootLayout.addWidget(this.topField);
this.rootLayout.addWidget(this.midField);
this.midLayout.addWidget(this.addRemoveButtonField,1,1);
this.midLayout.addWidget(this.selectAllCheckBox,1,0);
//this.helpButton.setGeometry(50,50,100,100)
this.helpButton.setText("?");
this.helpButton.addEventListener('clicked',()=> {
openHelpWindow();
});
this.fileDialog.setFileMode(FileMode.ExistingFiles);
//this.fileDialog.setNameFilter('../mount');
......@@ -84,7 +96,7 @@ export class CommitGUI {
this.midLayout.addWidget(this.usedBox,0,1);
this.usedBox.setLayout(this.usedBoxLayout)
this.usedBox.setTitle("prov:used")
this.usedBox.setTitle("Used")
this.usedBoxLayout.addWidget(this.usedList)
this.usedList.addEventListener('itemSelectionChanged',()=> {
......@@ -177,6 +189,7 @@ export class CommitGUI {
this.loadUncommitedChanges();
this.win.resize(400,300)
this.win.setCentralWidget(this.rootView);
this.win.show();
(global as any).commitWindow = this.win;
......@@ -353,6 +366,53 @@ export class CommitGUI {
}
}
function openHelpWindow() {
const helpWindow = new QMainWindow();
helpWindow.setWindowTitle("Help");
const helpView = new QWidget();
const helpLayout = new QGridLayout();
helpLayout.setVerticalSpacing(25)
helpView.setLayout(helpLayout)
const title = new QLabel();
title.setText("Title: ")
title.setInlineStyle("font-weight: bold;")
const helpTitle = new QLabel();
helpTitle.setText("Enter a title for your upload activity.")
title.setBuddy(helpTitle)
const changesLabel = new QLabel();
changesLabel.setText("Changes: ")
changesLabel.setInlineStyle("font-weight: bold;");
const helpChanges = new QLabel();
helpChanges.setText("Select which of your local changes you want to upload.")
const usedLabel = new QLabel();
usedLabel.setText("Used: ")
usedLabel.setInlineStyle("font-weight: bold;");
const helpUsed = new QLabel();
helpUsed.setText("Optional. Choose files to indicate that they were used in the selected changes.")
const commentLabel = new QLabel();
commentLabel.setText("Comment: ")
commentLabel.setInlineStyle("font-weight: bold;");
const helpComment = new QLabel();
helpComment.setText("Optional. Enter a comment to describe the upload activity. \nCan be useful to give more insight into changes.")
helpLayout.addWidget(helpTitle,0,1)
helpLayout.addWidget(title,0,0)
helpLayout.addWidget(helpChanges,1,1)
helpLayout.addWidget(changesLabel,1,0)
helpLayout.addWidget(helpUsed,2,1)
helpLayout.addWidget(usedLabel,2,0)
helpLayout.addWidget(helpComment,3,1)
helpLayout.addWidget(commentLabel,3,0)
helpWindow.setCentralWidget(helpView)
helpWindow.show();
(global as any).commitHelpWindow = helpWindow;
}
function start() {
try {
new CommitGUI()
......
const { QMainWindow, QSystemTrayIcon,QMenu, QAction,QApplication,QIcon,QStatusBar,QPushButton, WidgetEventTypes,QLabel, QWidget, FlexLayout,QGridLayout,ButtonRole, QBoxLayout,QLineEdit,QTextEdit,QGroupBox, QCheckBox,QFileDialog,FileMode,QListWidget,QListWidgetItem, QMessageBox } = require("@nodegui/nodegui");
const { QMainWindow, QToolButton,CursorShape,QSystemTrayIcon,QMenu, QAction,QApplication,QIcon,QStatusBar,QPushButton, WidgetEventTypes,QLabel, QWidget, FlexLayout,QGridLayout,ButtonRole, QBoxLayout,QLineEdit,QTextEdit,QGroupBox, QCheckBox,QFileDialog,FileMode,QListWidget,QListWidgetItem, QMessageBox } = require("@nodegui/nodegui");
const config = require('../config.json')
const fs = require('fs')
const pat = require('path')
......@@ -45,6 +45,9 @@ export class InitGUI {
unmountAction = new QAction();
autoCommitAction = new QAction();
helpButton = new QToolButton();
toolTipBar = new QStatusBar();
mounted:boolean;
constructor() {
......@@ -65,7 +68,8 @@ export class InitGUI {
const openAction = new QAction();
openAction.setText("Open GUI");
openAction.addEventListener('triggered',()=> {
this.win.setWindowState(2)
this.win.setWindowState(8)
this.win.raise();
});
trayMenu.addAction(openAction);
this.mountStatusAction.setText("No active mount");
......@@ -135,23 +139,47 @@ export class InitGUI {
this.rootView.setObjectName("rootView");
this.rootView.setLayout(this.rootLayout);
this.win.setStatusBar(this.toolTipBar);
this.toolTipBar.hide();
this.toolTipBar.showMessage("Hover over items for help")
this.rootLayout.addWidget(this.helpButton);
this.helpButton.setText("?");
this.helpButton.addEventListener('clicked',()=> {
openHelpWindow();
});
this.rootLayout.addWidget(this.inputArea);
this.inputArea.setLayout(this.inputLayout);
this.addressLabel.setBuddy(this.addressEdit)
//this.addressLabel.setCursor(CursorShape.PointingHandCursor)
this.addressLabel.addEventListener(WidgetEventTypes.ToolTip, () => {
//this.toolTipBar.show();
this.toolTipBar.showMessage("LDP Server: The server you want to connect to")
})
this.addressLabel.setText("LDP Server: ")
this.addressEdit.setText(config.ldpAddress)
this.inputLayout.addWidget(this.addressLabel,0,0)
this.inputLayout.addWidget(this.addressEdit,0,1)
this.userLabel.setBuddy(this.userEdit)
this.userLabel.addEventListener(WidgetEventTypes.ToolTip, () => {
//this.toolTipBar.show();
this.toolTipBar.showMessage("User ID: Your username")
})
this.userLabel.setText("User ID: ")
this.userEdit.setText(config.userID)
this.inputLayout.addWidget(this.userLabel,1,0)
this.inputLayout.addWidget(this.userEdit,1,1)
this.mountLabel.setBuddy(this.mountEdit)
this.mountLabel.setText("Target folder: ")
this.mountLabel.addEventListener(WidgetEventTypes.ToolTip, () => {
//this.toolTipBar.show();
this.toolTipBar.showMessage("Target: The folder where the files will be displayed")
})
this.mountLabel.setText("Target: ")
this.mountEdit.setText(config.mountpoint)
this.inputLayout.addWidget(this.mountLabel,2,0)
this.inputLayout.addWidget(this.mountEdit,2,1)
......@@ -165,6 +193,10 @@ export class InitGUI {
this.inputLayout.addWidget(this.mountFolderButton,2,2)
this.outputLabel.setBuddy(this.outputEdit)
this.outputLabel.addEventListener(WidgetEventTypes.ToolTip, () => {
//this.toolTipBar.show();
this.toolTipBar.showMessage("Download: The folder where downloaded files be saved")
})
this.outputLabel.setText("Download: ")
this.outputEdit.setText(config.output)
this.outputEdit.setReadOnly(true);
......@@ -181,21 +213,34 @@ export class InitGUI {
this.inputLayout.addWidget(this.autoCommitLabel,4,0);
this.autoCommitLabel.setText("Auto Sync: ");
this.autoCommitLabel.addEventListener(WidgetEventTypes.ToolTip, () => {
//this.toolTipBar.show();
this.toolTipBar.showMessage("Auto Sync: Select to automatically upload your changes")
})
this.inputLayout.addWidget(this.autoCommitBox,4,1);
this.autoCommitBox.setChecked(true);
this.autoCommitBox.addEventListener('stateChanged',()=> {
if(this.autoCommitBox.checkState()) {
this.autoCommitAction.setChecked(true);
config.autoCommitEnabled = true;
fuseFS.startAutoCommitter();
if(fuseFS) {
fuseFS.startAutoCommitter();
}
}
else {
this.autoCommitAction.setChecked(false);
config.autoCommitEnabled = false;