Skip to content

Commit

Permalink
set max simultaneous connections to 3
Browse files Browse the repository at this point in the history
  • Loading branch information
BastianGanze committed Jul 16, 2023
1 parent e6971d8 commit 4761e02
Show file tree
Hide file tree
Showing 13 changed files with 261 additions and 93 deletions.
8 changes: 2 additions & 6 deletions client/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -216,14 +216,14 @@
variant="text"
:icon="mdiContentCopy"
color="primary"
@click="copySyncMap($event, index)"
@click.stop="copySyncMap($event, index)"
/>
<v-btn
size="x-large"
variant="text"
:icon="mdiDelete"
color="error"
@click="deleteSyncMap($event, index)"
@click.stop="deleteSyncMap($event, index)"
/>
</span>
</div>
Expand Down Expand Up @@ -435,14 +435,10 @@ function addSyncMap() {
}
function deleteSyncMap(event: MouseEvent, index: number) {
event.preventDefault();
config.value.syncMaps.splice(index, 1);
}
function copySyncMap(event: MouseEvent, index: number) {
event.preventDefault();
config.value.syncMaps.splice(index + 1, 0, {
...config.value.syncMaps[index],
});
Expand Down
20 changes: 11 additions & 9 deletions client/src/FtpViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@
@click="onOpenModal()"
>
<v-icon
v-if="exists && !loading"
v-if="exists && !isLoading"
:icon="mdiCloudCheckVariant"
title="Directory exists"
/>
<v-icon
v-if="!exists && !loading"
v-if="!exists && !isLoading"
:icon="mdiCloudOff"
title="Directory does not exist"
/><v-progress-circular
v-if="loading"
v-if="isLoading"
indeterminate
width="2"
size="10"
Expand All @@ -43,11 +43,11 @@
<v-toolbar-items>
<v-btn
color="secondary"
:disabled="loading"
:disabled="isLoading"
@click="save()"
>
<v-progress-circular
v-if="loading"
v-if="isLoading"
indeterminate
width="2"
size="14"
Expand All @@ -59,15 +59,15 @@
<v-list v-model="selectedItem">
<v-list-item
v-if="!isRoot(current.path)"
:disabled="loading"
:disabled="isLoading"
@click="pathUp()"
>
..
</v-list-item>
<v-list-item
v-for="child in current.children"
:key="child.id"
:disabled="loading || !child.isDir"
:disabled="isLoading || !child.isDir"
@click="fetchDirectory(child.path)"
>
{{ child.name }}
Expand All @@ -81,7 +81,7 @@
<script lang="ts" setup>
import {PerfectScrollbar} from "vue3-perfect-scrollbar";
import {mdiClose, mdiCloudCheckVariant, mdiCloudOff} from "@mdi/js";
import {ref, watch} from "vue";
import {computed, ref, watch} from "vue";
import {useCommunication} from "./communication";
import {SyncMap} from "@shared/types";
Expand All @@ -95,6 +95,8 @@ interface TreeChild {
const emit = defineEmits(['save'])
const isLoading = computed(() => loading.value || exists.value === null);
function save() {
if (loading.value) {
return;
Expand All @@ -117,7 +119,7 @@ watch([ftpProps], () => {
}, {immediate: true})
const dialog = ref(false);
const exists = ref(false);
const exists = ref(null);
const loading = ref(false);
const selectedItem = ref(-1);
Expand Down
3 changes: 2 additions & 1 deletion client/src/communication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export class Communication {
public socket: Socket<ServerToClientEvents, ClientToServerEvents>;

constructor() {
this.socket = io('', {transports: ["websocket"]});
// eslint-disable-next-line no-undef
this.socket = io(__HOST__, {transports: ["websocket"]});
}

getVersion(cb: (version: string) => void) {
Expand Down
2 changes: 2 additions & 0 deletions client/src/shims-vue.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ declare module '*.vue' {
const component: DefineComponent<{}, {}, any>
export default component
}

declare var __HOST__: string;
42 changes: 24 additions & 18 deletions client/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
import { join } from "path";
import Vue from "@vitejs/plugin-vue";
import type { UserConfig } from "vite";
import UnpluginVueComponents from "unplugin-vue-components";
import VitePluginVuetify from "vite-plugin-vuetify";
import {defineConfig} from "vite";

const resolve = (dir: string) => join(__dirname, dir);

const config: UserConfig = {
resolve: {
alias: {
"@": resolve("src"),
},
},
base: "",
build: {
outDir: "../build/client",
target: "es2015",
},
plugins: [Vue(), UnpluginVueComponents.vite(), VitePluginVuetify()],
server: {
port: 8080,
},
};
export default defineConfig(
({command}) => {

export default config;
return {
resolve: {
alias: {
"@": resolve("src"),
},
},
base: "",
define: {
__HOST__: command === 'serve' ? '"http://0.0.0.0:42380"' : '""',
},
build: {
outDir: "../build/client",
target: "es2015",
},
plugins: [Vue(), UnpluginVueComponents.vite(), VitePluginVuetify()],
server: {
port: 8080,
},
};
}
);
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "weebsync",
"version": "0.6.4",
"version": "0.6.5",
"description": "A small tool to automatically sync files from an ftp server.",
"license": "MIT",
"private": true,
Expand Down
3 changes: 2 additions & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
"main": "./build/main.js",
"scripts": {
"build": "ts-node --skipProject build.ts && rollup -c --bundleConfigAsCjs && rm ../build/index.mjs",
"dev": "vite dev"
"dev": "esrun --watch=src/*.ts src/index.ts"
},
"author": "Bastian Ganze",
"devDependencies": {
"@digitak/esrun": "^3.2.24",
"@types/node": "^20.4.1",
"esbuild": "^0.18.11",
"rollup-plugin-esbuild": "^5.0.0",
Expand Down
4 changes: 4 additions & 0 deletions server/src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export async function listDir(path: string, applicationState: ApplicationState)
return await client.listDir(path);
} catch (err) {
applicationState.communication.logError(`FTP Connection error: ${err}"`);
} finally {
client.free();
}
})
.with({type: "ConnectionError", message: P.select()}, async (err) => {
Expand All @@ -25,6 +27,8 @@ export async function checkDir(path: string, applicationState: ApplicationState)
return true;
} catch (err) {
return false;
} finally {
client.free();
}
})
.with({ type: "ConnectionError", message: P.select() }, async (err) =>
Expand Down
5 changes: 0 additions & 5 deletions server/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,8 @@ import chokidar from "chokidar";
import { Config } from "@shared/types";
import { ApplicationState } from "./index";
import {Communication} from "./communication";

import { dirname } from 'path';
import { fileURLToPath } from 'url';
import process from "process";

const __dirname = dirname(fileURLToPath(import.meta.url));

const CONFIG_NAME = "weebsync.config.json";
export const PATH_TO_EXECUTABLE: string = process.cwd()
? process.cwd()
Expand Down
101 changes: 56 additions & 45 deletions server/src/ftp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,32 @@ export type CreateFtpClientResult =

export class FTP {
private _client = new Client();
private _busy: boolean = false;
private _used = false;
private _lastAction: Date = new Date();
constructor(
private _communication: Communication,
) {}

isBusy(): boolean {
return this._busy;
borrow() {
if (this._used) {
throw new Error("Tried to borrow while it was still borrowed?!");
}
this._used = true;
}

free() {
if (!this._used) {
throw new Error("Tried to free while it was already freed?!");
}
this._used = false;
}

available(): boolean {
return !this._used;
}

getLastAction(): Date {
return this._lastAction;
getLastActionTime(): number {
return this._lastAction.getTime();
}

async connect(config: Config) {
Expand All @@ -39,30 +53,13 @@ export class FTP {
}

async listDir(path: string): Promise<FileInfo[]> {
this._busy = true;
this._lastAction = new Date();
try {
const res = await this._client.list(path);
this._busy = false;
return res;
} catch (e) {
this._busy = false;
throw e;
}

return await this._client.list(path);
}

async cd(path: string): Promise<FTPResponse> {
this._busy = true;
this._lastAction = new Date();
try {
const res = await this._client.cd(path);
this._busy = false;
return res;
} catch (e) {
this._busy = false;
throw e;
}
return await this._client.cd(path);
}

close(): void {
Expand Down Expand Up @@ -98,46 +95,60 @@ export class FTP {
}
});

this._busy = true;
this._lastAction = new Date();
try {
await this._client.downloadTo(localFileStream, hostFilePath);
this._busy = false;
} finally {
this._communication.updateBottomBar(
{
fileProgress: "",
downloadSpeed: "",
},
{
fileProgress: "",
downloadSpeed: "",
},
);
} catch (e) {
this._busy = false;
this._communication.updateBottomBar({
fileProgress: "",
downloadSpeed: "",
});
throw e;
}
}
}

let ftps: FTP[] = [];
let ftpConnections: FTP[] = [];
const FTP_CONNECTION_TIMEOUT = 1000 * 60;
setInterval(() => {
ftps = ftps.filter(ftp => (Date.now() - ftp.getLastAction().getTime()) > FTP_CONNECTION_TIMEOUT );
cleanFTPConnections();
}, FTP_CONNECTION_TIMEOUT)

function cleanFTPConnections() {
ftpConnections = ftpConnections.filter(ftp => {
if ((Date.now() - ftp.getLastActionTime()) > FTP_CONNECTION_TIMEOUT || ftp.isClosed()) {
ftp.close();
return false;
}
return true;
} );
}

export async function getFTPClient(
config: Config,
communication: Communication,
): Promise<CreateFtpClientResult> {
try {
let ftp = ftps.find(f => !f.isBusy() && !f.isClosed());
if (!ftp) {
ftp = new FTP(communication);
ftps.push(ftp);
await ftp.connect(config);
console.log("---------");
for (const f of ftpConnections) {
console.log(`av ${f.available()} - cl ${f.isClosed()}`);
}
return { type: "Ok", data: ftp };
cleanFTPConnections();
let freeFtpConnection = ftpConnections.find(f => f.available() && !f.isClosed());
if (!freeFtpConnection) {
if (ftpConnections.length >= 3) {
await new Promise(resolve => setTimeout(resolve, 2000));
return await getFTPClient(config, communication);
}

freeFtpConnection = new FTP(communication);
ftpConnections.push(freeFtpConnection);
await freeFtpConnection.connect(config);
}

freeFtpConnection.borrow();
return {type: "Ok", data: freeFtpConnection };
} catch (err) {
return { type: "ConnectionError", message: err };
}
Expand Down
5 changes: 0 additions & 5 deletions server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ import {Communication} from "./communication";
import {join} from "path";
import {init} from "./init";

import { dirname } from 'path';
import { fileURLToPath } from 'url';

const __dirname = dirname(fileURLToPath(import.meta.url));

export interface ApplicationState {
config: Config;
configUpdateInProgress: boolean;
Expand Down
Loading

0 comments on commit 4761e02

Please sign in to comment.