Skip to content

Commit

Permalink
add import function
Browse files Browse the repository at this point in the history
  • Loading branch information
steve02081504 committed Jan 14, 2025
1 parent fc994a6 commit b964c71
Show file tree
Hide file tree
Showing 19 changed files with 338 additions and 120 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { locale_t } from "./basedefs";

export class charTemplateAPI_t {
export class importHanlderAPI_t {
info: Record<locale_t, {
name: string;
avatar: string;
Expand Down
12 changes: 12 additions & 0 deletions src/public/ImportHanlders/fount/git.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { mkdir, rm } from 'node:fs/promises'
import { exec } from "../../../scripts/exec.mjs"

export async function cloneRepo(repoUrl, targetDir) {
await mkdir(targetDir, { recursive: true })
try {
await exec(`git clone --depth 1 ${repoUrl} .`, { cwd: targetDir })
} catch (err) {
await rm(targetDir, { recursive: true, force: true })
throw err
}
}
60 changes: 60 additions & 0 deletions src/public/ImportHanlders/fount/main.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { unzipDirectory } from './zip.mjs'
import { cloneRepo } from './git.mjs'
import { getAvailablePath } from './path.mjs'
import { mkdir, rename, rm } from 'node:fs/promises'
import path from 'node:path'
import { tmpdir } from 'node:os'
import { loadJsonFile } from "../../../scripts/json_loader.mjs"

export default {
info: {
'': {
name: 'fount',
avatar: '',
description: 'default description',
description_markdown: 'default description',
version: '1.0.0',
author: 'steve02081504',
homepage: '',
tags: []
}
},
async ImportAsData(username, data) {
const tempDir = path.join(tmpdir(), 'fount_import_' + Date.now())
await mkdir(tempDir, { recursive: true })
try {
await unzipDirectory(data, tempDir)
} catch (err) {
console.error('Unzip failed:', err)
await rm(tempDir, { recursive: true, force: true })
throw new Error(`Unzip failed: ${err.message || err}`)
}
try {
let metaPath = path.join(tempDir, 'fount.json')
let meta = await loadJsonFile(metaPath)
let targetPath = await getAvailablePath(username, meta.type, meta.dirname)
await rename(tempDir, targetPath)
} catch (err) {
await rm(tempDir, { recursive: true, force: true })
throw new Error(`loadMeta failed: ${err.message || err}`)
}
},
async ImportByText(username, text) {
const lines = text.trim().split('\n').map(line => line.trim()).filter(line => line)
for (const line of lines)
if (line.startsWith('http')) {
const tempDir = path.join(tmpdir(), 'fount_import_git_' + Date.now())
try {
await cloneRepo(line, tempDir)
let metaPath = path.join(tempDir, 'fount.json')
let meta = await loadJsonFile(metaPath)
let targetPath = await getAvailablePath(username, meta.type, meta.dirname)
await rename(tempDir, targetPath)
} catch (err) {
console.error(`Git clone failed for ${line}:`, err)
await rm(tempDir, { recursive: true, force: true })
throw new Error(`Git clone failed for ${line}: ${err.message || err}`)
}
}
}
}
16 changes: 16 additions & 0 deletions src/public/ImportHanlders/fount/path.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import path from 'node:path'
import fs from 'node:fs'
import { getUserDictionary } from "../../../server/auth.mjs"

export function resolvePath(username, type, name) {
let userPath = getUserDictionary(username)
let partPath = path.join(userPath, type, name)
return partPath
}

export function getAvailablePath(username, type, name) {
let targetPath = resolvePath(username, type, name)
if (fs.existsSync(targetPath))
fs.rmSync(targetPath, { recursive: true, force: true })
return targetPath
}
71 changes: 71 additions & 0 deletions src/public/ImportHanlders/fount/zip.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import jszip from 'npm:jszip'
import { writeFile, mkdir, readdir, stat, readFile } from 'node:fs/promises'
import path from 'node:path'
import { Buffer } from "node:buffer"

async function zipDirectory(dirPath, zip) {

const items = await readdir(dirPath)

for (const item of items) {
const itemPath = path.join(dirPath, item)
const itemStat = await stat(itemPath)

if (itemStat.isDirectory())
await zipDirectory(itemPath, zip.folder(item)) // 递归压缩目录
else {
const content = await readFile(itemPath)
zip.file(item, content)
}
}
}

export async function zipDir(dirPath) {
const zip = new jszip()
await zipDirectory(dirPath, zip)
return zip.generateAsync({ type: 'nodebuffer' })
}

export async function unzipDirectory(buffer, targetPath) {
try {
const zip = new jszip()
await zip.loadAsync(buffer)

for (const zipEntry of Object.values(zip.files))
if (zipEntry.dir) {
// 如果是目录,则创建目录
const dirPath = path.join(targetPath, zipEntry.name)
await mkdir(dirPath, { recursive: true })
console.log(`Created directory: ${dirPath}`)
} else {
// 如果是文件,则写入文件
const filePath = path.join(targetPath, zipEntry.name)
const fileBuffer = await zipEntry.async('nodebuffer')
await mkdir(path.dirname(filePath), { recursive: true })
await writeFile(filePath, fileBuffer)
console.log(`Wrote file: ${filePath}`)
}
} catch (err) {
console.error('unzip error:',err)
throw err
}
}

export async function readZipfile(buffer, zipPath) {
const zip = new jszip()
await zip.loadAsync(buffer)
const file = zip.files[zipPath]
if (!file || file.dir)
throw new Error(`File not found in ZIP: ${zipPath}`)

return await file.async('nodebuffer')
}

export async function readZipfileAsJSON(buffer, zipPath) {
try {
let filebuffer = await readZipfile(buffer, zipPath)
return JSON.parse(filebuffer.toString())
} catch (err) {
throw new Error(`Failed to parse JSON file in ZIP ${zipPath}, ${err.message||err}`)
}
}
14 changes: 0 additions & 14 deletions src/public/charTemplates/fount/main.mjs

This file was deleted.

3 changes: 1 addition & 2 deletions src/public/home/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ async function initializeApp() {
}
displayCharList()
importButton.addEventListener('click', () => {
// TODO: 发送导入角色请求
alert('逻辑未完成')
window.location = '/shells/install'
})
}

Expand Down
71 changes: 61 additions & 10 deletions src/public/shells/install/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ function handleFiles(files) {
if (!selectedFiles.find(f => f.name === file.name))
selectedFiles.push(file)


renderFileList()
}

Expand All @@ -79,14 +78,66 @@ async function renderFileList() {
}

// 导入按钮点击事件
importButton.addEventListener('click', () => {
importButton.addEventListener('click', async () => {
const isFileImport = !fileImportContent.classList.contains('hidden')
if (isFileImport)
// 处理文件导入逻辑
console.log('导入文件:', selectedFiles)
else
// 处理文本导入逻辑
console.log('导入文本:', textInput.value)

// 在这里调用你的导入函数入口
try {
if (isFileImport)
await handleFileImport()
else
await handleTextImport()

alert('导入成功')
} catch (error) {
let errorMessage = error.message || 'Unknown error'
if (error.errors)
errorMessage += `\n${formatErrors(error.errors)}`

alert(`导入失败: ${errorMessage}`)
}
})


async function handleFileImport() {
if (selectedFiles.length === 0)
throw new Error('请选择文件')

const formData = new FormData()
for (const file of selectedFiles)
formData.append('files', file)

const response = await fetch('/api/shells/install/file', {
method: 'POST',
body: formData
})

if (!response.ok) {
const result = await response.json()
const error = new Error(`文件导入失败: ${result.message || 'Unknown error'}`)
error.errors = result.errors
throw error
}
}
async function handleTextImport() {
const text = textInput.value
if (!text)
throw new Error('请输入文本内容')

const response = await fetch('/api/shells/install/text', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ text })
})

if (!response.ok) {
const result = await response.json()
const error = new Error(`文本导入失败: ${result.message || 'Unknown error'}`)
error.errors = result.errors
throw error
}
}

function formatErrors(errors) {
return errors.map(err => `handler: ${err.hanlder}, Error: ${err.error}`).join(';\n')
}
52 changes: 35 additions & 17 deletions src/public/shells/install/src/server/Installer_handler.mjs
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
import { LoadCharTemplate } from "./charTemplate_manager.mjs"
import { LoadImportHanlder } from "./importHanlder_manager.mjs"
import { getPartList } from '../../../../../server/parts_loader.mjs'

export async function importChar(username, data) {
let charTemplates = getPartList(username, 'charTemplates')
for (let charTemplate of charTemplates) try {
let template = await LoadCharTemplate(username, charTemplate)
await template.ImportChar(username, data)
} catch (err) {
console.log(err)
}
export async function importPart(username, data) {
let ImportHanlders = getPartList(username, 'ImportHanlders')
const errors = []

for (let importHanlder of ImportHanlders)
try {
let hanlder = await LoadImportHanlder(username, importHanlder)
await hanlder.ImportAsData(username, data)
return
} catch (err) {
errors.push({ hanlder: importHanlder, error: err.message || String(err) })
console.log(`hanlder ${importHanlder} failed:`, err)
}

// 如果所有模板都失败,抛出包含所有错误的异常
if (errors.length > 0)
throw Object.assign(new Error("All hanlders failed"), { errors })
}

export async function importCharByText(username, text) {
let charTemplates = getPartList(username, 'charTemplates')
for (let charTemplate of charTemplates) try {
let template = await LoadCharTemplate(username, charTemplate)
await template.ImportCharByText(username, text)
} catch (err) {
console.log(err)
}
export async function importPartByText(username, text) {
let ImportHanlders = getPartList(username, 'ImportHanlders')
const errors = []

for (let importHanlder of ImportHanlders)
try {
let hanlder = await LoadImportHanlder(username, importHanlder)
await hanlder.ImportByText(username, text)
return
} catch (err) {
errors.push({ hanlder: importHanlder, error: err.message || String(err) })
console.log(`hanlder ${importHanlder} failed:`, err)
}


if (errors.length > 0)
throw Object.assign(new Error("All hanlders failed"), { errors })
}
22 changes: 0 additions & 22 deletions src/public/shells/install/src/server/charTemplate_manager.mjs

This file was deleted.

Loading

0 comments on commit b964c71

Please sign in to comment.