Implement file content access functionality.

This commit is contained in:
zhengyi59 2024-03-02 10:15:39 -05:00
parent 6142653b3e
commit 210a3d38a0
5 changed files with 162 additions and 44 deletions

View File

@ -0,0 +1,59 @@
import { AgentSocketHandler } from "../agent-socket-handler";
import {callbackResult, checkLogin, DockgeSocket, ValidationError} from "../util-server";
import { DockgeServer } from "../dockge-server";
import { AgentSocket } from "../../common/agent-socket";
import { log } from "../log";
import { Stack } from "../stack";
export class FileSocketHandler extends AgentSocketHandler {
create(socket: DockgeSocket, server: DockgeServer, agentSocket: AgentSocket) {
agentSocket.on("listDir", async (stackName: unknown, path: unknown, callback) => {
try {
checkLogin(socket);
if (typeof(path) !== "string") {
throw new ValidationError("Path must be a string");
}
const stack = await this.getStack(server, stackName);
const res = await stack.listFiles(path);
callbackResult({
ok: true,
files: res
}, callback);
} catch (e) {
if (e instanceof Error) {
log.warn("agent", e.message);
}
}
});
agentSocket.on("getFile", async (stackName: unknown, file: unknown, callback) => {
try {
checkLogin(socket);
if (typeof(file) !== "string") {
throw new ValidationError("File Path must be a string");
}
const stack = await this.getStack(server, stackName);
const content = await stack.getFile(file);
callbackResult({
ok: true,
content: content,
}, callback);
} catch (e) {
if (e instanceof Error) {
log.warn("agent", e.message);
}
}
});
}
async getStack(server : DockgeServer, stackName: unknown) {
if (typeof(stackName) !== "string") {
throw new ValidationError("Stack name must be a string");
}
return await Stack.getStack(server, stackName);
}
}

View File

@ -37,6 +37,7 @@ import { AgentSocketHandler } from "./agent-socket-handler";
import { AgentSocket } from "../common/agent-socket";
import { ManageAgentSocketHandler } from "./socket-handlers/manage-agent-socket-handler";
import { Terminal } from "./terminal";
import {FileSocketHandler} from "./agent-socket-handlers/file-socket-handler";
export class DockgeServer {
app : Express;
@ -69,6 +70,7 @@ export class DockgeServer {
agentSocketHandlerList : AgentSocketHandler[] = [
new DockerSocketHandler(),
new TerminalSocketHandler(),
new FileSocketHandler(),
];
/**

View File

@ -547,4 +547,27 @@ export class Stack {
}
}
async listFiles(p: string) {
const dataDir = path.join(this.dataDir, p);
const files = await fsAsync.readdir(dataDir);
const filePromises = files.map(async file => {
const filePath = path.join(dataDir, file);
const stats = await fsAsync.stat(filePath);
return {
name: file,
path: path.join(p, file),
folder: stats.isDirectory(),
};
});
return Promise.all(filePromises);
}
async getFile(p: string) {
const file = path.join(this.dataDir, p);
console.log(file);
const content = await fsAsync.readFile(file, "utf-8");
log.debug("file", content);
return content;
}
}

View File

@ -1,4 +1,4 @@
<script setup lang="ts">
<script lang="ts">
import { highlight, languages } from "prismjs/components/prism-core";
import { PrismEditor } from "vue-prism-editor";
import "prismjs/themes/prism-dark.css";
@ -7,13 +7,9 @@ import "vue-prism-editor/dist/prismeditor.min.css";
import "prismjs/components/prism-json.js";
import "prismjs/components/prism-yaml";
import { ref } from "vue";
import { defineComponent, ref } from "vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import {FileDef} from "../util-frontend";
const code = ref<string>("");
const opened = ref<boolean>(false);
import { FileDef } from "../util-frontend";
const allLanguage = [
{
@ -28,41 +24,68 @@ const allLanguage = [
}
];
const language = ref({
label: "YAML",
value: "yaml",
lang: languages.yaml
});
export default defineComponent({
name: "FileEditor",
components: {
PrismEditor,
},
props: {
endpoint: {
type: String,
required: true
},
stackName: {
type: String,
required: true
}
},
data() {
return {
allLanguage: allLanguage,
code: "",
opened: false,
disabled: false,
language: {
label: "YAML",
value: "yaml",
lang: languages.yaml
},
fileInfo: {
name: "UNTITLED",
path: "",
folder: false,
}
};
},
methods: {
languageChange(e) {
const res = allLanguage.filter(lang => lang.value === e.target.value);
if (res.length <= 0) {
this.language = allLanguage[0];
} else {
this.language = res[0];
}
},
const fileInfo = ref<FileDef>({
name: "UNTITLED",
path: "",
folder: false,
});
open(file: FileDef) {
this.opened = true;
this.disabled = true;
this.fileInfo = file;
this.$root.emitAgent(this.endpoint, "getFile", this.stackName, file.path, (res) => {
this.code = res.content;
this.disabled = false;
});
},
const languageChange = (e) => {
const res = allLanguage.filter(lang => lang.value === e.target.value);
if (res.length <= 0) {
language.value = allLanguage[0];
} else {
language.value = res[0];
close() {
this.opened = false;
},
highlighter(code) {
return highlight(code, this.language.lang, this.language.value);
},
}
};
const open = (file: FileDef) => {
opened.value = true;
fileInfo.value = file;
};
const close = () => {
opened.value = false;
};
defineExpose({ open });
const highlighter = (code) => {
return highlight(code, language.value.lang, language.value.value);
};
});
</script>
<template>
@ -79,7 +102,7 @@ const highlighter = (code) => {
</select>
</div>
<div class="editor-wrapper">
<PrismEditor v-model="code" class="my-editor" :highlight="highlighter" line-numbers />
<PrismEditor v-model="code" class="my-editor" :readonly="disabled" :highlight="highlighter" line-numbers />
</div>
</div>
</div>

View File

@ -1,10 +1,11 @@
<script lang="ts">
import { defineComponent } from "vue";
import {FontAwesomeIcon} from "@fortawesome/vue-fontawesome";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { log } from "../../../backend/log";
export default defineComponent({
name: "Files",
components: {FontAwesomeIcon},
components: { FontAwesomeIcon },
data() {
return {
files: [
@ -27,6 +28,16 @@ export default defineComponent({
stackName() {
return this.$route.params.stackName;
},
endpoint() {
return this.$route.params.endpoint || "";
},
},
mounted() {
this.$root.emitAgent(this.endpoint, "listDir", "homepage", "/", (res) => {
console.log(res.files);
this.files = res.files;
});
},
methods: {
open(file) {
@ -38,7 +49,7 @@ export default defineComponent({
this.$refs.fileEditor.open(file);
}
},
}
},
});
</script>
@ -86,7 +97,7 @@ export default defineComponent({
/>
</div>
<FileEditor ref="fileEditor" />
<FileEditor :endpoint="endpoint" :stack-name="stackName" ref="fileEditor" />
</div>
</transition>
</template>