Initial commit
This commit is contained in:
833
skills/walrus-code-generator.md
Normal file
833
skills/walrus-code-generator.md
Normal file
@@ -0,0 +1,833 @@
|
||||
---
|
||||
name: walrus-code-generator
|
||||
description: 自动生成 Walrus TypeScript SDK 集成代码和最佳实践模板
|
||||
parameters:
|
||||
- name: use-case
|
||||
type: string
|
||||
description: 使用场景 (basic-upload/advanced-storage/browser-app/batch-processing)
|
||||
required: true
|
||||
- name: framework
|
||||
type: string
|
||||
description: 开发框架 (react/vue/nodejs/nextjs/express)
|
||||
default: nodejs
|
||||
- name: features
|
||||
type: array
|
||||
description: 需要的功能特性
|
||||
default: []
|
||||
- name: environment
|
||||
type: string
|
||||
description: 部署环境 (development/production)
|
||||
default: development
|
||||
---
|
||||
|
||||
# Walrus 代码生成技能
|
||||
|
||||
## 技能概述
|
||||
|
||||
`walrus-code-generator` 是一个专业的代码生成助手,根据您的具体需求自动生成 Walrus TypeScript SDK 集成代码。支持多种使用场景、开发框架和部署环境,确保生成的代码符合最佳实践。
|
||||
|
||||
## 支持的使用场景
|
||||
|
||||
### 1. 基础文件上传 (basic-upload)
|
||||
|
||||
```typescript
|
||||
// 自动生成的基础上传服务
|
||||
skill: "walrus-code-generator"
|
||||
// use-case: basic-upload
|
||||
// framework: nodejs
|
||||
// features: ["error-handling", "progress-tracking"]
|
||||
|
||||
export class BasicWalrusUploader {
|
||||
private client: any;
|
||||
private signer: any;
|
||||
|
||||
constructor(network: 'testnet' | 'mainnet' = 'testnet') {
|
||||
const suiClient = new SuiJsonRpcClient({
|
||||
url: getFullnodeUrl(network),
|
||||
network,
|
||||
}).$extend(walrus());
|
||||
|
||||
this.client = suiClient;
|
||||
this.signer = this.createSigner();
|
||||
}
|
||||
|
||||
async uploadFile(
|
||||
filePath: string,
|
||||
options: UploadOptions = {}
|
||||
): Promise<UploadResult> {
|
||||
const {
|
||||
epochs = 10,
|
||||
deletable = true,
|
||||
tags = {},
|
||||
onProgress = () => {}
|
||||
} = options;
|
||||
|
||||
try {
|
||||
onProgress(25, '读取文件...');
|
||||
|
||||
const fs = await import('fs/promises');
|
||||
const fileContent = await fs.readFile(filePath);
|
||||
const fileName = filePath.split('/').pop() || 'unknown';
|
||||
|
||||
onProgress(50, '创建 Walrus 文件...');
|
||||
|
||||
const file = WalrusFile.from({
|
||||
contents: fileContent,
|
||||
identifier: `uploads/${Date.now()}_${fileName}`,
|
||||
mimeType: this.getMimeType(filePath),
|
||||
attributes: {
|
||||
'original-path': filePath,
|
||||
'file-size': fileContent.length.toString(),
|
||||
'upload-time': new Date().toISOString(),
|
||||
...tags
|
||||
}
|
||||
});
|
||||
|
||||
onProgress(75, '上传到网络...');
|
||||
|
||||
const result = await this.client.walrus.writeFiles({
|
||||
files: [file],
|
||||
epochs,
|
||||
deletable,
|
||||
signer: this.signer
|
||||
});
|
||||
|
||||
onProgress(100, '上传完成');
|
||||
|
||||
return {
|
||||
success: true,
|
||||
blobId: result[0].blobId,
|
||||
fileName,
|
||||
size: fileContent.length,
|
||||
storedUntil: result[0].storedUntil
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('上传失败:', error.message);
|
||||
throw new Error(`上传失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
private createSigner(): Ed25519Keypair {
|
||||
const privateKey = process.env.WALRUS_PRIVATE_KEY;
|
||||
if (!privateKey) {
|
||||
throw new Error('未找到私钥环境变量 WALRUS_PRIVATE_KEY');
|
||||
}
|
||||
return Ed25519Keypair.fromSecretKey(privateKey);
|
||||
}
|
||||
|
||||
private getMimeType(filePath: string): string {
|
||||
const ext = filePath.split('.').pop()?.toLowerCase();
|
||||
const mimeTypes: Record<string, string> = {
|
||||
'txt': 'text/plain',
|
||||
'pdf': 'application/pdf',
|
||||
'jpg': 'image/jpeg',
|
||||
'png': 'image/png',
|
||||
'json': 'application/json'
|
||||
};
|
||||
return mimeTypes[ext || ''] || 'application/octet-stream';
|
||||
}
|
||||
}
|
||||
|
||||
interface UploadOptions {
|
||||
epochs?: number;
|
||||
deletable?: boolean;
|
||||
tags?: Record<string, string>;
|
||||
onProgress?: (progress: number, message: string) => void;
|
||||
}
|
||||
|
||||
interface UploadResult {
|
||||
success: boolean;
|
||||
blobId: string;
|
||||
fileName: string;
|
||||
size: number;
|
||||
storedUntil: Date;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 高级存储管理 (advanced-storage)
|
||||
|
||||
```typescript
|
||||
// 自动生成的高级存储管理服务
|
||||
skill: "walrus-code-generator"
|
||||
// use-case: advanced-storage
|
||||
// framework: nodejs
|
||||
// features: ["batch-operations", "retry-logic", "cache-management", "metadata-indexing"]
|
||||
|
||||
export class AdvancedWalrusStorage {
|
||||
private client: any;
|
||||
private signer: any;
|
||||
private cache: Map<string, CachedFile> = new Map();
|
||||
private retryConfig: RetryConfig;
|
||||
|
||||
constructor(options: AdvancedStorageOptions = {}) {
|
||||
const {
|
||||
network = 'testnet',
|
||||
retryAttempts = 3,
|
||||
retryDelay = 1000,
|
||||
cacheEnabled = true,
|
||||
cacheTTL = 300000 // 5分钟
|
||||
} = options;
|
||||
|
||||
const suiClient = new SuiJsonRpcClient({
|
||||
url: getFullnodeUrl(network),
|
||||
network,
|
||||
}).$extend(walrus({
|
||||
storageNodeClientOptions: {
|
||||
timeout: 60000,
|
||||
onError: (error) => console.warn('存储节点错误:', error)
|
||||
}
|
||||
}));
|
||||
|
||||
this.client = suiClient;
|
||||
this.signer = this.createSigner();
|
||||
this.retryConfig = { attempts: retryAttempts, delay: retryDelay };
|
||||
this.cacheEnabled = cacheEnabled;
|
||||
this.cacheTTL = cacheTTL;
|
||||
}
|
||||
|
||||
async batchUpload(
|
||||
files: FileUploadRequest[],
|
||||
options: BatchUploadOptions = {}
|
||||
): Promise<BatchUploadResult> {
|
||||
const {
|
||||
epochs = 10,
|
||||
deletable = true,
|
||||
maxConcurrency = 3,
|
||||
commonTags = {}
|
||||
} = options;
|
||||
|
||||
const results: UploadResult[] = [];
|
||||
const errors: UploadError[] = [];
|
||||
|
||||
// 分批处理
|
||||
for (let i = 0; i < files.length; i += maxConcurrency) {
|
||||
const batch = files.slice(i, i + maxConcurrency);
|
||||
|
||||
const batchPromises = batch.map(async (fileRequest, index) => {
|
||||
try {
|
||||
const result = await this.uploadWithRetry(fileRequest, {
|
||||
epochs,
|
||||
deletable,
|
||||
tags: { ...commonTags, ...fileRequest.tags }
|
||||
});
|
||||
|
||||
results.push({
|
||||
...result,
|
||||
originalPath: fileRequest.path,
|
||||
batchIndex: i + index
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
errors.push({
|
||||
originalPath: fileRequest.path,
|
||||
error: error.message,
|
||||
batchIndex: i + index
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(batchPromises);
|
||||
|
||||
// 批次间延迟
|
||||
if (i + maxConcurrency < files.length) {
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
totalFiles: files.length,
|
||||
successful: results.length,
|
||||
failed: errors.length,
|
||||
results,
|
||||
errors
|
||||
};
|
||||
}
|
||||
|
||||
async smartDownload(
|
||||
blobId: string,
|
||||
options: SmartDownloadOptions = {}
|
||||
): Promise<SmartDownloadResult> {
|
||||
const {
|
||||
forceRefresh = false,
|
||||
verifyIntegrity = true,
|
||||
cacheKey = blobId
|
||||
} = options;
|
||||
|
||||
// 检查缓存
|
||||
if (!forceRefresh && this.cacheEnabled) {
|
||||
const cached = this.getFromCache(cacheKey);
|
||||
if (cached) {
|
||||
console.log('从缓存返回文件:', blobId);
|
||||
return {
|
||||
...cached,
|
||||
fromCache: true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.downloadWithVerification(blobId, verifyIntegrity);
|
||||
|
||||
// 缓存结果
|
||||
if (this.cacheEnabled) {
|
||||
this.setToCache(cacheKey, result);
|
||||
}
|
||||
|
||||
return {
|
||||
...result,
|
||||
fromCache: false
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
throw new Error(`智能下载失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async searchByTags(tags: Record<string, string>): Promise<SearchResult[]> {
|
||||
// 这是一个概念性实现
|
||||
// 实际搜索需要基于您自己的元数据索引系统
|
||||
const indexedFiles = await this.getIndexedFiles();
|
||||
|
||||
return indexedFiles.filter(file => {
|
||||
return Object.entries(tags).every(([key, value]) =>
|
||||
file.tags[key] === value
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private async uploadWithRetry(
|
||||
fileRequest: FileUploadRequest,
|
||||
options: UploadOptions
|
||||
): Promise<UploadResult> {
|
||||
const { attempts, delay } = this.retryConfig;
|
||||
|
||||
for (let attempt = 1; attempt <= attempts; attempt++) {
|
||||
try {
|
||||
return await this.uploadSingleFile(fileRequest, options);
|
||||
} catch (error) {
|
||||
if (attempt < attempts && this.isRetryableError(error)) {
|
||||
console.log(`上传失败,第 ${attempt} 次重试...`);
|
||||
await new Promise(resolve => setTimeout(resolve, delay * attempt));
|
||||
continue;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('上传失败,已达到最大重试次数');
|
||||
}
|
||||
|
||||
private async uploadSingleFile(
|
||||
fileRequest: FileUploadRequest,
|
||||
options: UploadOptions
|
||||
): Promise<UploadResult> {
|
||||
const fs = await import('fs/promises');
|
||||
const fileContent = await fs.readFile(fileRequest.path);
|
||||
|
||||
const file = WalrusFile.from({
|
||||
contents: fileContent,
|
||||
identifier: fileRequest.identifier || `files/${Date.now()}_${fileRequest.path}`,
|
||||
mimeType: fileRequest.mimeType || this.getMimeType(fileRequest.path),
|
||||
attributes: {
|
||||
'original-path': fileRequest.path,
|
||||
'file-size': fileContent.length.toString(),
|
||||
'upload-time': new Date().toISOString(),
|
||||
...options.tags
|
||||
}
|
||||
});
|
||||
|
||||
const result = await this.client.walrus.writeFiles({
|
||||
files: [file],
|
||||
epochs: options.epochs,
|
||||
deletable: options.deletable,
|
||||
signer: this.signer
|
||||
});
|
||||
|
||||
// 索引文件元数据
|
||||
await this.indexFile({
|
||||
blobId: result[0].blobId,
|
||||
identifier: file.identifier,
|
||||
path: fileRequest.path,
|
||||
size: fileContent.length,
|
||||
tags: options.tags,
|
||||
uploadTime: new Date()
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
blobId: result[0].blobId,
|
||||
identifier: file.identifier,
|
||||
size: fileContent.length,
|
||||
storedUntil: result[0].storedUntil
|
||||
};
|
||||
}
|
||||
|
||||
private async downloadWithVerification(
|
||||
blobId: string,
|
||||
verify: boolean
|
||||
): Promise<SmartDownloadResult> {
|
||||
const [file] = await this.client.walrus.getFiles({ ids: [blobId] });
|
||||
|
||||
const exists = await file.exists();
|
||||
if (!exists) {
|
||||
throw new Error(`文件不存在: ${blobId}`);
|
||||
}
|
||||
|
||||
const content = await file.bytes();
|
||||
let verified = true;
|
||||
|
||||
if (verify) {
|
||||
const verification = await this.verifyFileIntegrity(blobId, content);
|
||||
verified = verification.valid;
|
||||
}
|
||||
|
||||
return {
|
||||
blobId,
|
||||
content: Buffer.from(content),
|
||||
size: content.length,
|
||||
storedUntil: await file.storedUntil(),
|
||||
verified,
|
||||
metadata: await this.getFileMetadata(file)
|
||||
};
|
||||
}
|
||||
|
||||
private async verifyFileIntegrity(
|
||||
blobId: string,
|
||||
content: Uint8Array
|
||||
): Promise<{ valid: boolean; error?: string }> {
|
||||
try {
|
||||
// 基本完整性检查
|
||||
if (content.length === 0) {
|
||||
return { valid: false, error: '文件内容为空' };
|
||||
}
|
||||
|
||||
// 这里可以添加更复杂的验证逻辑
|
||||
return { valid: true };
|
||||
} catch (error) {
|
||||
return { valid: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存管理
|
||||
private getFromCache(key: string): CachedFile | null {
|
||||
const cached = this.cache.get(key);
|
||||
if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
|
||||
return cached;
|
||||
}
|
||||
this.cache.delete(key);
|
||||
return null;
|
||||
}
|
||||
|
||||
private setToCache(key: string, file: SmartDownloadResult): void {
|
||||
this.cache.set(key, {
|
||||
...file,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
private isRetryableError(error: any): boolean {
|
||||
return error instanceof RetryableWalrusClientError ||
|
||||
error.message.includes('timeout') ||
|
||||
error.message.includes('network');
|
||||
}
|
||||
}
|
||||
|
||||
// 类型定义
|
||||
interface FileUploadRequest {
|
||||
path: string;
|
||||
identifier?: string;
|
||||
mimeType?: string;
|
||||
tags?: Record<string, string>;
|
||||
}
|
||||
|
||||
interface BatchUploadOptions {
|
||||
epochs?: number;
|
||||
deletable?: boolean;
|
||||
maxConcurrency?: number;
|
||||
commonTags?: Record<string, string>;
|
||||
}
|
||||
|
||||
interface BatchUploadResult {
|
||||
totalFiles: number;
|
||||
successful: number;
|
||||
failed: number;
|
||||
results: (UploadResult & { originalPath: string; batchIndex: number })[];
|
||||
errors: UploadError[];
|
||||
}
|
||||
|
||||
interface SmartDownloadOptions {
|
||||
forceRefresh?: boolean;
|
||||
verifyIntegrity?: boolean;
|
||||
cacheKey?: string;
|
||||
}
|
||||
|
||||
interface SmartDownloadResult {
|
||||
blobId: string;
|
||||
content: Buffer;
|
||||
size: number;
|
||||
storedUntil: Date;
|
||||
verified: boolean;
|
||||
metadata: any;
|
||||
fromCache: boolean;
|
||||
}
|
||||
|
||||
interface CachedFile extends SmartDownloadResult {
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
interface RetryConfig {
|
||||
attempts: number;
|
||||
delay: number;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. React 浏览器应用 (browser-app)
|
||||
|
||||
```typescript
|
||||
// 自动生成的 React Hook 和组件
|
||||
skill: "walrus-code-generator"
|
||||
// use-case: browser-app
|
||||
// framework: react
|
||||
// features: ["wallet-integration", "progress-tracking", "drag-drop"]
|
||||
|
||||
import React, { useState, useCallback, createContext, useContext } from 'react';
|
||||
import { useWallet } from '@suiet/wallet-kit';
|
||||
|
||||
// Walrus Context
|
||||
const WalrusContext = createContext<{
|
||||
upload: (files: FileList) => Promise<UploadResult[]>;
|
||||
download: (blobId: string, filename?: string) => Promise<void>;
|
||||
isUploading: boolean;
|
||||
} | null>(null);
|
||||
|
||||
export const WalrusProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const { connected, signAndExecuteTransactionBlock } = useWallet();
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
|
||||
const upload = useCallback(async (files: FileList): Promise<UploadResult[]> => {
|
||||
if (!connected) {
|
||||
throw new Error('请先连接钱包');
|
||||
}
|
||||
|
||||
setIsUploading(true);
|
||||
const results: UploadResult[] = [];
|
||||
|
||||
try {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
|
||||
try {
|
||||
const result = await uploadFile(file, signAndExecuteTransactionBlock);
|
||||
results.push({ ...result, originalName: file.name, index: i });
|
||||
} catch (error) {
|
||||
results.push({
|
||||
success: false,
|
||||
originalName: file.name,
|
||||
index: i,
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
setIsUploading(false);
|
||||
}
|
||||
|
||||
return results;
|
||||
}, [connected, signAndExecuteTransactionBlock]);
|
||||
|
||||
const download = useCallback(async (blobId: string, filename?: string) => {
|
||||
await downloadFile(blobId, filename);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<WalrusContext.Provider value={{ upload, download, isUploading }}>
|
||||
{children}
|
||||
</WalrusContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useWalrus = () => {
|
||||
const context = useContext(WalrusContext);
|
||||
if (!context) {
|
||||
throw new Error('useWalrus must be used within WalrusProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
// 文件上传组件
|
||||
export const WalrusUpload: React.FC<{
|
||||
onUploadComplete?: (results: UploadResult[]) => void;
|
||||
maxFiles?: number;
|
||||
acceptedTypes?: string;
|
||||
}> = ({ onUploadComplete, maxFiles = 10, acceptedTypes = '*' }) => {
|
||||
const { upload, isUploading } = useWalrus();
|
||||
const [dragActive, setDragActive] = useState(false);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const fileInputRef = React.useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleFiles = useCallback(async (files: FileList) => {
|
||||
if (files.length > maxFiles) {
|
||||
alert(`最多只能上传 ${maxFiles} 个文件`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setProgress(10);
|
||||
const results = await upload(files);
|
||||
setProgress(100);
|
||||
onUploadComplete?.(results);
|
||||
} catch (error) {
|
||||
alert(`上传失败: ${error.message}`);
|
||||
setProgress(0);
|
||||
}
|
||||
}, [upload, maxFiles, onUploadComplete]);
|
||||
|
||||
const handleDrop = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setDragActive(false);
|
||||
|
||||
const files = e.dataTransfer.files;
|
||||
if (files.length > 0) {
|
||||
handleFiles(files);
|
||||
}
|
||||
}, [handleFiles]);
|
||||
|
||||
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const files = e.target.files;
|
||||
if (files && files.length > 0) {
|
||||
handleFiles(files);
|
||||
}
|
||||
}, [handleFiles]);
|
||||
|
||||
return (
|
||||
<div className="walrus-upload">
|
||||
<div
|
||||
className={`upload-area ${dragActive ? 'active' : ''} ${isUploading ? 'uploading' : ''}`}
|
||||
onDragEnter={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setDragActive(true);
|
||||
}}
|
||||
onDragLeave={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setDragActive(false);
|
||||
}}
|
||||
onDragOver={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
onDrop={handleDrop}
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
multiple
|
||||
accept={acceptedTypes}
|
||||
onChange={handleChange}
|
||||
style={{ display: 'none' }}
|
||||
/>
|
||||
|
||||
{isUploading ? (
|
||||
<div className="upload-progress">
|
||||
<div className="progress-bar">
|
||||
<div
|
||||
className="progress-fill"
|
||||
style={{ width: `${progress}%` }}
|
||||
/>
|
||||
</div>
|
||||
<p>上传中... {progress}%</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="upload-prompt">
|
||||
<div className="upload-icon">📁</div>
|
||||
<h3>拖拽文件到此处或点击上传</h3>
|
||||
<p>支持最多 {maxFiles} 个文件</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// 文件列表组件
|
||||
export const WalrusFileList: React.FC<{
|
||||
files: UploadResult[];
|
||||
onDownload?: (blobId: string, filename: string) => void;
|
||||
}> = ({ files, onDownload }) => {
|
||||
const { download } = useWalrus();
|
||||
|
||||
const handleDownload = useCallback(async (blobId: string, filename: string) => {
|
||||
try {
|
||||
await onDownload ? onDownload(blobId, filename) : download(blobId, filename);
|
||||
} catch (error) {
|
||||
alert(`下载失败: ${error.message}`);
|
||||
}
|
||||
}, [download, onDownload]);
|
||||
|
||||
return (
|
||||
<div className="file-list">
|
||||
<h3>文件列表</h3>
|
||||
{files.map((file, index) => (
|
||||
<div key={index} className={`file-item ${file.success ? 'success' : 'error'}`}>
|
||||
<div className="file-info">
|
||||
<span className="file-name">{file.originalName}</span>
|
||||
{file.success ? (
|
||||
<span className="file-success">✓ 上传成功</span>
|
||||
) : (
|
||||
<span className="file-error">✗ {file.error}</span>
|
||||
)}
|
||||
</div>
|
||||
{file.success && file.blobId && (
|
||||
<div className="file-actions">
|
||||
<button
|
||||
onClick={() => handleDownload(file.blobId!, file.originalName)}
|
||||
className="download-btn"
|
||||
>
|
||||
下载
|
||||
</button>
|
||||
<span className="blob-id">{file.blobId.slice(0, 16)}...</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// 辅助函数
|
||||
async function uploadFile(
|
||||
file: File,
|
||||
signAndExecuteTransactionBlock: any
|
||||
): Promise<UploadResult> {
|
||||
const arrayBuffer = await file.arrayBuffer();
|
||||
const walrusFile = WalrusFile.from({
|
||||
contents: new Uint8Array(arrayBuffer),
|
||||
identifier: `browser/${Date.now()}_${file.name}`,
|
||||
mimeType: file.type,
|
||||
attributes: {
|
||||
'original-name': file.name,
|
||||
'file-size': file.size.toString(),
|
||||
'upload-source': 'browser'
|
||||
}
|
||||
});
|
||||
|
||||
const suiClient = new SuiClient({
|
||||
url: getFullnodeUrl('testnet'),
|
||||
});
|
||||
|
||||
const walrusClient = new WalrusClient({
|
||||
network: 'testnet',
|
||||
suiClient,
|
||||
});
|
||||
|
||||
const writeFlow = walrusClient.walrus.writeFilesFlow({
|
||||
files: [walrusFile],
|
||||
epochs: 10,
|
||||
deletable: true
|
||||
});
|
||||
|
||||
const result = await writeFlow.executeWithSigner({
|
||||
signAndExecuteTransactionBlock
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
blobId: result[0].blobId,
|
||||
size: file.size
|
||||
};
|
||||
}
|
||||
|
||||
async function downloadFile(blobId: string, filename?: string) {
|
||||
// 实现文件下载逻辑
|
||||
const link = document.createElement('a');
|
||||
link.href = `#download-${blobId}`;
|
||||
link.download = filename || 'downloaded-file';
|
||||
link.click();
|
||||
}
|
||||
|
||||
interface UploadResult {
|
||||
success: boolean;
|
||||
blobId?: string;
|
||||
size?: number;
|
||||
originalName: string;
|
||||
index: number;
|
||||
error?: string;
|
||||
}
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 基础代码生成
|
||||
```typescript
|
||||
skill: "walrus-code-generator"
|
||||
// use-case: basic-upload
|
||||
// framework: nodejs
|
||||
// features: ["error-handling", "logging"]
|
||||
```
|
||||
|
||||
### React 应用生成
|
||||
```typescript
|
||||
skill: "walrus-code-generator"
|
||||
// use-case: browser-app
|
||||
// framework: react
|
||||
// features: ["wallet-integration", "drag-drop", "progress-bar"]
|
||||
```
|
||||
|
||||
### 高级存储系统
|
||||
```typescript
|
||||
skill: "walrus-code-generator"
|
||||
// use-case: advanced-storage
|
||||
// framework: nodejs
|
||||
// features: ["batch-operations", "caching", "retry-logic", "metadata-indexing"]
|
||||
```
|
||||
|
||||
### 批量处理系统
|
||||
```typescript
|
||||
skill: "walrus-code-generator"
|
||||
// use-case: batch-processing
|
||||
// framework: express
|
||||
// features: ["api-endpoints", "queue-system", "monitoring"]
|
||||
```
|
||||
|
||||
## 生成的代码特性
|
||||
|
||||
### 🛡️ 错误处理
|
||||
- 智能重试机制
|
||||
- 详细错误信息
|
||||
- 优雅降级策略
|
||||
|
||||
### 📊 进度跟踪
|
||||
- 实时上传进度
|
||||
- 批量操作状态
|
||||
- 性能监控
|
||||
|
||||
### 🔧 配置管理
|
||||
- 灵活的配置选项
|
||||
- 环境适配
|
||||
- 类型安全
|
||||
|
||||
### 🚀 性能优化
|
||||
- 缓存机制
|
||||
- 并发控制
|
||||
- 内存管理
|
||||
|
||||
### 🔒 安全考虑
|
||||
- 输入验证
|
||||
- 文件完整性检查
|
||||
- 访问控制
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **错误处理** - 生成的代码包含完整的错误处理逻辑
|
||||
2. **类型安全** - 使用 TypeScript 提供完整的类型定义
|
||||
3. **性能优化** - 包含缓存、批量处理和并发控制
|
||||
4. **可扩展性** - 模块化设计,易于扩展和维护
|
||||
5. **监控日志** - 集成日志记录和性能监控
|
||||
|
||||
---
|
||||
|
||||
*更新时间:2025-11-11*
|
||||
Reference in New Issue
Block a user