Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:47:53 +08:00
commit eca77537f8
7 changed files with 3254 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
{
"name": "walrus-ts",
"description": "Walrus TypeScript SDK 专业化 AI 技能集,提供代码生成、错误诊断、监控分析和性能优化功能,专为 Walrus 去中心化存储应用开发者打造",
"version": "1.0.0",
"author": {
"name": "icehugh",
"url": "https://github.com/icehugh"
},
"skills": [
"./skills/walrus-code-generator.md",
"./skills/walrus-debugger.md",
"./skills/walrus-monitor.md",
"./skills/walrus-performance-optimizer.md"
]
}

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# walrus-ts
Walrus TypeScript SDK 专业化 AI 技能集,提供代码生成、错误诊断、监控分析和性能优化功能,专为 Walrus 去中心化存储应用开发者打造

57
plugin.lock.json Normal file
View File

@@ -0,0 +1,57 @@
{
"$schema": "internal://schemas/plugin.lock.v1.json",
"pluginId": "gh:IceHugh/web3-skills:plugins/walrus-ts",
"normalized": {
"repo": null,
"ref": "refs/tags/v20251128.0",
"commit": "06d68ff1bf73ce56b1d9e51b692e8c69277090b2",
"treeHash": "64320018af6f422c00f00245e9acab8eee6a96350c8d4b0254b190f8419e4376",
"generatedAt": "2025-11-28T10:11:42.066243Z",
"toolVersion": "publish_plugins.py@0.2.0"
},
"origin": {
"remote": "git@github.com:zhongweili/42plugin-data.git",
"branch": "master",
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
},
"manifest": {
"name": "walrus-ts",
"description": "Walrus TypeScript SDK 专业化 AI 技能集,提供代码生成、错误诊断、监控分析和性能优化功能,专为 Walrus 去中心化存储应用开发者打造",
"version": "1.0.0"
},
"content": {
"files": [
{
"path": "README.md",
"sha256": "c83f9e4d8d2f29b7530bb5ae2c1d5de617ff56cfd8e4d8072600c6a033e87d93"
},
{
"path": ".claude-plugin/plugin.json",
"sha256": "dbbf5f4988e401c731ec8cfe4f222e50917f81b88847b9ce2d7a09768eb5db07"
},
{
"path": "skills/walrus-debugger.md",
"sha256": "08c4cc9a125b1d339e17cfdedd1bba446cbfb6608bdb4c9e9348985a1b6e2486"
},
{
"path": "skills/walrus-monitor.md",
"sha256": "177168c232f00d9a8c32f91901a7c37165921e41f219f1dc10eb74c38f4abf53"
},
{
"path": "skills/walrus-code-generator.md",
"sha256": "369009349d62f07b85df07655e447dccaba50579a533ee16f149481f158855d9"
},
{
"path": "skills/walrus-performance-optimizer.md",
"sha256": "e8a5b724f84d5966fca546a5c3d6f7bd6a9759a1e328cc102c99433a302380c9"
}
],
"dirSha256": "64320018af6f422c00f00245e9acab8eee6a96350c8d4b0254b190f8419e4376"
},
"security": {
"scannedAt": null,
"scannerVersion": null,
"flags": []
}
}

View 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*

828
skills/walrus-debugger.md Normal file
View File

@@ -0,0 +1,828 @@
---
name: walrus-debugger
description: Walrus 错误诊断专家 - 智能分析和解决 Walrus 应用中的问题
parameters:
- name: error-type
type: string
description: 错误类型 (upload/download/network/configuration/timeout/authentication)
required: true
- name: error-context
type: string
description: 错误信息、代码片段或问题描述
required: true
- name: environment
type: string
description: 运行环境 (browser/nodejs/nextjs/production)
default: nodejs
---
# Walrus 错误诊断技能
## 技能概述
`walrus-debugger` 是专业的错误诊断助手,专门分析 Walrus 应用中的各种问题,提供智能的解决方案和预防措施。
## 常见错误类型及解决方案
### 1. 上传失败错误
#### 错误类型: Upload Failed
```typescript
// 错误示例
Error: Upload failed: insufficient storage balance
Error: Upload failed: blob size exceeds maximum limit
Error: Upload failed: transaction rejected
// 诊断和解决方案
class UploadErrorDiagnostics {
async diagnoseUploadError(error: Error, context: UploadContext): Promise<Diagnosis> {
const analysis = this.analyzeErrorMessage(error.message);
switch (analysis.type) {
case 'INSUFFICIENT_BALANCE':
return this.diagnoseBalanceError(context);
case 'SIZE_LIMIT':
return this.diagnoseSizeError(context);
case 'TRANSACTION_REJECTED':
return this.diagnoseTransactionError(error, context);
case 'TIMEOUT':
return this.diagnoseTimeoutError(context);
default:
return this.diagnoseGenericUploadError(error, context);
}
}
private async diagnoseBalanceError(context: UploadContext): Promise<Diagnosis> {
const walletBalance = await this.checkWalletBalance(context.signerAddress);
return {
errorType: 'INSUFFICIENT_BALANCE',
description: '钱包余额不足,无法支付存储费用',
causes: [
'WAL 代币余额不足',
'SUI 代币余额不足以支付 gas 费',
'存储成本计算错误'
],
solutions: [
{
title: '检查并充值钱包',
code: `
// 检查钱包余额
async function checkBalances(address: string) {
const suiClient = new SuiClient({ url: getFullnodeUrl('testnet') });
const balance = await suiClient.getBalance({ owner: address });
console.log('SUI Balance:', balance.totalBalance);
// 检查 WAL 余额(如果支持)
const walBalance = await suiClient.getBalance({
owner: address,
coinType: '0x2::sui::SUI' // 替换为 WAL coin type
});
return { sui: balance.totalBalance, wal: walBalance.totalBalance };
}`
},
{
title: '优化存储策略',
code: `
// 使用更短的存储周期
const result = await client.walrus.writeFiles({
files: [file],
epochs: 5, // 减少存储周期
deletable: true,
signer: keypair
});
// 或者使用更小的文件
function compressFile(file: File): Promise<File> {
return new Promise((resolve) => {
if (file.size > 10 * 1024 * 1024) { // 10MB
// 压缩或分割文件
compressImage(file).then(resolve);
} else {
resolve(file);
}
});
}`
}
],
prevention: [
'定期检查钱包余额',
'设置余额预警',
'实施费用估算功能'
]
};
}
private async diagnoseSizeError(context: UploadContext): Promise<Diagnosis> {
const fileStats = await this.analyzeFileSize(context.file);
return {
errorType: 'SIZE_LIMIT',
description: '文件大小超出限制',
causes: [
`文件大小 ${fileStats.size}MB 超出限制`,
'网络环境不支持大文件传输',
'客户端内存不足'
],
solutions: [
{
title: '文件压缩',
code: `
// 图片压缩
async function compressImage(file: File, quality = 0.8): Promise<File> {
return new Promise((resolve) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d')!;
const img = new Image();
img.onload = () => {
// 计算压缩后的尺寸
const scale = Math.min(1, 1920 / Math.max(img.width, img.height));
canvas.width = img.width * scale;
canvas.height = img.height * scale;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
canvas.toBlob((blob) => {
resolve(new File([blob!], file.name, { type: file.type }));
}, file.type, quality);
};
img.src = URL.createObjectURL(file);
});
}
// 文本文件压缩
async function compressTextFile(file: File): Promise<File> {
const text = await file.text();
const compressed = await this.compressString(text);
return new File([compressed], file.name + '.gz', { type: 'application/gzip' });
}`
},
{
title: '文件分割上传',
code: `
// 分割大文件
async function splitAndUpload(file: File, chunkSize = 5 * 1024 * 1024): Promise<string[]> {
const chunks: string[] = [];
const totalChunks = Math.ceil(file.size / chunkSize);
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const chunk = file.slice(start, end);
const chunkFile = new File([chunk], \`\${file.name}.part\${i}\`);
const result = await uploadSingleFile(chunkFile);
chunks.push(result.blobId);
}
return chunks;
}
// 创建清单文件记录分割信息
async function createManifest(chunks: string[], originalFile: File): Promise<string> {
const manifest = {
originalName: originalFile.name,
originalSize: originalFile.size,
chunks: chunks.map((blobId, index) => ({
blobId,
index,
size: originalFile.size / chunks.length
}))
};
const manifestBlob = new Blob([JSON.stringify(manifest)], { type: 'application/json' });
const manifestFile = new File([manifestBlob], \`\${originalFile.name}.manifest\`);
const result = await uploadSingleFile(manifestFile);
return result.blobId;
}`
}
],
prevention: [
'预先检查文件大小',
'实施文件大小限制',
'提供文件压缩工具'
]
};
}
}
```
### 2. 网络连接错误
#### 错误类型: Network Error
```typescript
// 错误示例
Error: Network timeout
Error: Connection refused
Error: Failed to fetch
class NetworkErrorDiagnostics {
async diagnoseNetworkError(error: Error, context: NetworkContext): Promise<Diagnosis> {
const networkStatus = await this.checkNetworkStatus();
return {
errorType: 'NETWORK_ERROR',
description: '网络连接问题',
causes: [
'网络连接不稳定',
'RPC 节点不可用',
'防火墙或代理阻止连接',
'DNS 解析失败'
],
solutions: [
{
title: '实施自动重试机制',
code: `
class RobustWalrusClient {
private readonly MAX_RETRIES = 3;
private readonly RETRY_DELAY_BASE = 1000;
async withRetry<T>(
operation: () => Promise<T>,
operationName: string
): Promise<T> {
for (let attempt = 1; attempt <= this.MAX_RETRIES; attempt++) {
try {
return await operation();
} catch (error) {
if (!this.isRetryableError(error) || attempt === this.MAX_RETRIES) {
throw new Error(\`\${operationName} failed after \${attempt} attempts: \${error.message}\`);
}
const delay = this.RETRY_DELAY_BASE * Math.pow(2, attempt - 1);
console.warn(\`\${operationName} failed (attempt \${attempt}/\${this.MAX_RETRIES}), retrying in \${delay}ms\`);
await this.sleep(delay);
}
}
throw new Error('Should not reach here');
}
private isRetryableError(error: any): boolean {
return error instanceof RetryableWalrusClientError ||
error.message.includes('timeout') ||
error.message.includes('network') ||
error.message.includes('connection') ||
error.status >= 500; // Server errors
}
private sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
async uploadFiles(files: WalrusFile[]): Promise<any> {
return this.withRetry(
() => this.client.walrus.writeFiles({ files, epochs: 10, signer: this.signer }),
'File upload'
);
}
}`
},
{
title: '实施节点健康检查',
code: `
// 节点健康检查
class NodeHealthChecker {
private nodes: string[] = [
'https://fullnode.testnet.sui.io',
'https://fullnode.testnet.sui.io:443',
// 添加备用节点
];
async getHealthyNode(): Promise<string> {
for (const node of this.nodes) {
try {
const response = await fetch(\`\${node}/\`, {
method: 'HEAD',
timeout: 5000
});
if (response.ok) {
console.log(\`Node \${node} is healthy\`);
return node;
}
} catch (error) {
console.warn(\`Node \${node} is unhealthy: \${error.message}\`);
}
}
throw new Error('No healthy nodes available');
}
async testAllNodes(): Promise<NodeHealth[]> {
const results = await Promise.allSettled(
this.nodes.map(async (node) => {
const startTime = Date.now();
try {
const response = await fetch(\`\${node}/\`, { method: 'HEAD', timeout: 5000 });
return {
node,
healthy: response.ok,
responseTime: Date.now() - startTime,
error: null
};
} catch (error) {
return {
node,
healthy: false,
responseTime: Date.now() - startTime,
error: error.message
};
}
})
);
return results.map(result =>
result.status === 'fulfilled' ? result.value : null
).filter(Boolean) as NodeHealth[];
}
}`
},
{
title: '配置超时和重试',
code: `
// 配置自定义超时和重试
const client = new SuiJsonRpcClient({
url: getFullnodeUrl('testnet'),
network: 'testnet',
}).$extend(walrus({
storageNodeClientOptions: {
timeout: 60000, // 60秒超时
retryAttempts: 5,
retryDelay: 2000,
onError: (error) => {
console.error('Storage node error:', error);
// 发送错误到监控系统
this.trackError('storage_node_error', error);
}
}
}));`
}
],
prevention: [
'实施网络监控',
'使用多个备用节点',
'设置合理的超时时间',
'实施断路器模式'
]
};
}
private async checkNetworkStatus(): Promise<NetworkStatus> {
try {
const response = await fetch('https://httpbin.org/ip');
const ipInfo = await response.json();
return {
online: true,
ip: ipInfo.ip,
latency: Date.now() - this.startTime
};
} catch (error) {
return {
online: false,
error: error.message
};
}
}
}
```
### 3. 配置错误
#### 错误类型: Configuration Error
```typescript
// 错误示例
Error: Invalid network configuration
Error: WASM module failed to load
Error: Invalid signer configuration
class ConfigurationErrorDiagnostics {
async diagnoseConfigError(error: Error, context: ConfigContext): Promise<Diagnosis> {
return {
errorType: 'CONFIGURATION_ERROR',
description: '配置问题',
causes: [
'网络配置错误',
'WASM 模块路径错误',
'签名者配置无效',
'环境变量缺失'
],
solutions: [
{
title: '验证配置完整性',
code: `
// 配置验证器
class ConfigValidator {
static validateWalrusConfig(config: any): ValidationResult {
const errors: string[] = [];
// 验证必需字段
if (!config.network) {
errors.push('network is required (testnet/mainnet)');
}
if (!config.rpcUrl) {
errors.push('rpcUrl is required');
}
// 验证网络配置
if (config.network && !['testnet', 'mainnet'].includes(config.network)) {
errors.push('network must be either "testnet" or "mainnet"');
}
// 验证 URL 格式
if (config.rpcUrl && !this.isValidUrl(config.rpcUrl)) {
errors.push('rpcUrl must be a valid URL');
}
// 验证超时配置
if (config.timeout && (config.timeout < 1000 || config.timeout > 300000)) {
errors.push('timeout must be between 1000ms and 300000ms');
}
return {
valid: errors.length === 0,
errors
};
}
static async validateEnvironment(): Promise<ValidationResult> {
const errors: string[] = [];
// 检查环境变量
const requiredEnvVars = ['WALRUS_NETWORK', 'SUI_RPC_URL'];
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
errors.push(\`Environment variable \${envVar} is required\`);
}
}
// 检查 WASM 支持
if (typeof window !== 'undefined' && !window.WebAssembly) {
errors.push('WebAssembly is not supported in this browser');
}
// 验证网络连接
try {
const response = await fetch(process.env.SUI_RPC_URL!, {
method: 'HEAD',
timeout: 5000
});
if (!response.ok) {
errors.push('Cannot connect to SUI RPC endpoint');
}
} catch (error) {
errors.push(\`Network connection failed: \${error.message}\`);
}
return {
valid: errors.length === 0,
errors
};
}
private static isValidUrl(string: string): boolean {
try {
new URL(string);
return true;
} catch {
return false;
}
}
}
// 使用配置验证
const config = {
network: 'testnet',
rpcUrl: getFullnodeUrl('testnet'),
timeout: 30000
};
const validation = ConfigValidator.validateWalrusConfig(config);
if (!validation.valid) {
console.error('Configuration validation failed:', validation.errors);
throw new Error('Invalid configuration');
}`
},
{
title: 'WASM 模块配置',
code: `
// WASM 配置验证和加载
class WasmLoader {
static async loadWasmWithFallback(): Promise<any> {
const strategies = [
() => this.loadFromBundle(),
() => this.loadFromCDN(),
() => this.loadFromLocal()
];
for (const strategy of strategies) {
try {
const wasm = await strategy();
console.log('WASM loaded successfully');
return wasm;
} catch (error) {
console.warn('WASM loading strategy failed:', error.message);
}
}
throw new Error('All WASM loading strategies failed');
}
private static async loadFromBundle(): Promise<any> {
// Vite 示例
if (typeof import.meta !== 'undefined' && import.meta.url) {
const wasmUrl = new URL('@mysten/walrus-wasm/web/walrus_wasm_bg.wasm', import.meta.url);
const wasmModule = await import(wasmUrl);
return wasmModule.default;
}
throw new Error('Bundle loading not supported');
}
private static async loadFromCDN(): Promise<any> {
const cdnUrls = [
'https://unpkg.com/@mysten/walrus-wasm@latest/web/walrus_wasm_bg.wasm',
'https://cdn.jsdelivr.net/npm/@mysten/walrus-wasm@latest/web/walrus_wasm_bg.wasm'
];
for (const url of cdnUrls) {
try {
const response = await fetch(url);
if (response.ok) {
const wasmBuffer = await response.arrayBuffer();
return WebAssembly.compile(wasmBuffer);
}
} catch (error) {
console.warn(\`CDN loading failed for \${url}:\`, error.message);
}
}
throw new Error('All CDN URLs failed');
}
private static async loadFromLocal(): Promise<any> {
// 尝试从本地路径加载
const localPaths = [
'/walrus/walrus_wasm_bg.wasm',
'./node_modules/@mysten/walrus-wasm/web/walrus_wasm_bg.wasm'
];
for (const path of localPaths) {
try {
const response = await fetch(path);
if (response.ok) {
const wasmBuffer = await response.arrayBuffer();
return WebAssembly.compile(wasmBuffer);
}
} catch (error) {
console.warn(\`Local loading failed for \${path}:\`, error.message);
}
}
throw new Error('Local loading failed');
}
}
// 在客户端配置中使用 WASM
const client = new SuiJsonRpcClient({
url: getFullnodeUrl('testnet'),
network: 'testnet',
}).$extend(
walrus({
wasmUrl: await WasmLoader.loadWasmWithFallback()
})
);`
}
],
prevention: [
'实施配置验证',
'提供配置模板',
'设置默认值',
'实施配置监控'
]
};
}
}
```
### 4. 浏览器环境特定错误
#### 错误类型: Browser Environment Error
```typescript
class BrowserErrorDiagnostics {
async diagnoseBrowserError(error: Error, context: BrowserContext): Promise<Diagnosis> {
return {
errorType: 'BROWSER_ERROR',
description: '浏览器环境特定问题',
causes: [
'WASM 不支持',
'CORS 策略阻止',
'内存不足',
'钱包连接问题'
],
solutions: [
{
title: '浏览器兼容性检查',
code: `
// 浏览器兼容性检查
class BrowserCompatibility {
static checkCompatibility(): BrowserCompatibilityResult {
const checks = {
webAssembly: this.checkWebAssembly(),
fetch: this.checkFetch(),
blob: this.checkBlob(),
fileAPI: this.checkFileAPI(),
webWorkers: this.checkWebWorkers(),
localStorage: this.checkLocalStorage()
};
const supported = Object.values(checks).every(check => check.supported);
return {
supported,
checks,
recommendations: this.getRecommendations(checks)
};
}
private static checkWebAssembly(): CompatibilityCheck {
const supported = typeof WebAssembly === 'object' && WebAssembly !== null;
return {
supported,
message: supported ? 'WebAssembly is supported' : 'WebAssembly is not supported',
fix: !supported ? 'Please use a modern browser that supports WebAssembly' : null
};
}
private static getRecommendations(checks: Record<string, CompatibilityCheck>): string[] {
const recommendations: string[] = [];
if (!checks.webAssembly.supported) {
recommendations.push('Upgrade to a modern browser (Chrome 57+, Firefox 52+, Safari 11+)');
}
if (!checks.webWorkers.supported) {
recommendations.push('Consider enabling Web Workers for better performance');
}
return recommendations;
}
}
// 使用兼容性检查
const compatibility = BrowserCompatibility.checkCompatibility();
if (!compatibility.supported) {
console.error('Browser compatibility issues:', compatibility.recommendations);
// 显示用户友好的错误信息
this.showCompatibilityError(compatibility);
}`
},
{
title: '内存管理',
code: `
// 浏览器内存管理
class BrowserMemoryManager {
private memoryThreshold = 100 * 1024 * 1024; // 100MB
async checkMemoryUsage(): Promise<MemoryUsage> {
if ('memory' in performance) {
const memory = (performance as any).memory;
return {
used: memory.usedJSHeapSize,
total: memory.totalJSHeapSize,
limit: memory.jsHeapSizeLimit,
usageRatio: memory.usedJSHeapSize / memory.jsHeapSizeLimit
};
}
return { used: 0, total: 0, limit: 0, usageRatio: 0 };
}
async manageMemoryForLargeFile(file: File): Promise<boolean> {
const memoryUsage = await this.checkMemoryUsage();
// 检查是否有足够内存处理文件
const estimatedUsage = file.size * 3; // 估算处理过程中需要的内存
const availableMemory = memoryUsage.limit - memoryUsage.used;
if (estimatedUsage > availableMemory) {
console.warn('Insufficient memory for file processing');
// 触发垃圾回收(如果可能)
if (window.gc) {
window.gc();
}
// 重新检查内存
const newUsage = await this.checkMemoryUsage();
return (file.size * 3) < (newUsage.limit - newUsage.used);
}
return true;
}
// 流式处理大文件
async processLargeFileInChunks(
file: File,
processor: (chunk: Uint8Array) => Promise<void>,
chunkSize = 1024 * 1024 // 1MB
): Promise<void> {
const reader = new FileReader();
let offset = 0;
const processChunk = () => {
if (offset >= file.size) {
return Promise.resolve();
}
return new Promise<void>((resolve, reject) => {
const chunk = file.slice(offset, offset + chunkSize);
reader.onload = async (event) => {
try {
if (event.target?.result) {
const arrayBuffer = event.target.result as ArrayBuffer;
const uint8Array = new Uint8Array(arrayBuffer);
await processor(uint8Array);
offset += chunkSize;
// 检查内存使用
const memoryUsage = await this.checkMemoryUsage();
if (memoryUsage.usageRatio > 0.8) {
console.warn('High memory usage, forcing garbage collection');
if (window.gc) window.gc();
}
await processChunk();
}
resolve();
} catch (error) {
reject(error);
}
};
reader.onerror = () => reject(new Error('File reading failed'));
reader.readAsArrayBuffer(chunk);
});
};
return processChunk();
}
}`
}
],
prevention: [
'实施浏览器兼容性检查',
'监控内存使用',
'提供降级方案',
'实施优雅错误处理'
]
};
}
}
```
## 使用方法
### 上传错误诊断
```typescript
skill: "walrus-debugger"
// error-type: upload
// error-context: Upload failed: insufficient storage balance, trying to upload 10MB file to testnet
// environment: browser
```
### 网络连接问题
```typescript
skill: "walrus-debugger"
// error-type: network
// error-context: Network timeout when connecting to storage nodes, intermittent connection issues
// environment: production
```
### 配置验证
```typescript
skill: "walrus-debugger"
// error-type: configuration
// error-context: WASM module failed to load in Vite production build, error: "Failed to resolve module"
// environment: nodejs
```
### 性能问题
```typescript
skill: "walrus-debugger"
// error-type: performance
// error-context: Memory usage spikes when uploading multiple large files, browser crashes
// environment: browser
```
---
*更新时间2025-11-11*

757
skills/walrus-monitor.md Normal file
View File

@@ -0,0 +1,757 @@
---
name: walrus-monitor
description: Walrus 监控分析专家 - 存储使用监控、成本分析和性能指标跟踪
parameters:
- name: monitor-type
type: string
description: 监控类型 (usage/cost/performance/errors/analytics)
required: true
- name: time-range
type: string
description: 时间范围 (1h/24h/7d/30d/custom)
default: 24h
- name: metrics
type: array
description: 需要监控的具体指标
default: []
---
# Walrus 监控分析技能
## 技能概述
`walrus-monitor` 是专业的监控分析助手,提供全面的 Walrus 存储系统监控、成本分析和性能指标跟踪功能,帮助开发者优化资源使用和控制成本。
## 监控维度
### 1. 存储使用监控
#### 实时存储指标
```typescript
class StorageMonitor {
private metrics: StorageMetrics[] = [];
private alerts: Alert[] = [];
async collectStorageMetrics(): Promise<StorageMetrics> {
const client = await this.getWalrusClient();
const accountAddress = this.getAccountAddress();
// 获取账户存储信息
const storageInfo = await client.getStorageInfo(accountAddress);
const blobIds = storageInfo.storedBlobs || [];
// 计算存储统计
const metrics: StorageMetrics = {
timestamp: Date.now(),
totalFiles: blobIds.length,
totalSize: 0,
totalCost: 0,
storageDistribution: {},
fileAges: [],
oldestFile: null,
newestFile: null,
expiringSoon: [],
expired: []
};
// 分析每个文件
for (const blobId of blobIds) {
try {
const [file] = await client.walrus.getFiles({ ids: [blobId] });
const metadata = await this.getFileMetadata(file);
const storedUntil = await file.storedUntil();
metrics.totalSize += metadata.size;
metrics.totalCost += metadata.estimatedCost;
// 文件类型分布
const fileType = this.getFileType(metadata.mimeType);
metrics.storageDistribution[fileType] =
(metrics.storageDistribution[fileType] || 0) + 1;
// 文件年龄分析
const age = Date.now() - metadata.uploadTime;
metrics.fileAges.push(age);
// 检查过期状态
const daysToExpiry = Math.floor((storedUntil.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
if (daysToExpiry < 7) {
metrics.expiringSoon.push({
blobId,
fileName: metadata.identifier,
daysToExpiry,
size: metadata.size
});
}
if (daysToExpiry < 0) {
metrics.expired.push({
blobId,
fileName: metadata.identifier,
daysExpired: Math.abs(daysToExpiry),
size: metadata.size
});
}
// 更新最新和最旧文件
if (!metrics.oldestFile || age > metrics.oldestFile.age) {
metrics.oldestFile = {
blobId,
fileName: metadata.identifier,
age,
uploadDate: new Date(metadata.uploadTime)
};
}
if (!metrics.newestFile || age < metrics.newestFile.age) {
metrics.newestFile = {
blobId,
fileName: metadata.identifier,
age,
uploadDate: new Date(metadata.uploadTime)
};
}
} catch (error) {
console.warn(`Failed to analyze blob ${blobId}:`, error.message);
}
}
// 存储指标历史
this.metrics.push(metrics);
if (this.metrics.length > 1000) {
this.metrics.shift(); // 保留最近1000条记录
}
// 检查告警条件
this.checkStorageAlerts(metrics);
return metrics;
}
private checkStorageAlerts(metrics: StorageMetrics): void {
// 存储空间告警
if (metrics.totalSize > 100 * 1024 * 1024 * 1024) { // 100GB
this.createAlert({
type: 'STORAGE_LIMIT',
severity: 'WARNING',
message: `存储使用量达到 ${this.formatBytes(metrics.totalSize)}`,
recommendation: '考虑清理过期文件或升级存储计划'
});
}
// 文件数量告警
if (metrics.totalFiles > 10000) {
this.createAlert({
type: 'FILE_COUNT_LIMIT',
severity: 'INFO',
message: `文件数量达到 ${metrics.totalFiles}`,
recommendation: '考虑实施文件归档策略'
});
}
// 即将过期告警
if (metrics.expiringSoon.length > 0) {
this.createAlert({
type: 'EXPIRING_FILES',
severity: 'WARNING',
message: `${metrics.expiringSoon.length} 个文件将在7天内过期`,
recommendation: '续期或备份重要文件'
});
}
}
getStorageTrends(timeRange: number = 7 * 24 * 60 * 60 * 1000): StorageTrends {
const cutoff = Date.now() - timeRange;
const relevantMetrics = this.metrics.filter(m => m.timestamp >= cutoff);
if (relevantMetrics.length < 2) {
return {
growthRate: 0,
costGrowthRate: 0,
fileGrowthRate: 0,
projectedUsage: null,
projectedCost: null
};
}
const oldest = relevantMetrics[0];
const newest = relevantMetrics[relevantMetrics.length - 1];
const timeDiff = newest.timestamp - oldest.timestamp;
return {
growthRate: this.calculateGrowthRate(oldest.totalSize, newest.totalSize, timeDiff),
costGrowthRate: this.calculateGrowthRate(oldest.totalCost, newest.totalCost, timeDiff),
fileGrowthRate: this.calculateGrowthRate(oldest.totalFiles, newest.totalFiles, timeDiff),
projectedUsage: this.projectUsage(newest.totalSize, this.calculateGrowthRate(oldest.totalSize, newest.totalSize, timeDiff)),
projectedCost: this.projectCost(newest.totalCost, this.calculateGrowthRate(oldest.totalCost, newest.totalCost, timeDiff))
};
}
}
```
### 2. 成本分析
#### 成本监控和优化
```typescript
class CostAnalyzer {
private costHistory: CostRecord[] = [];
private pricingModel: PricingModel;
constructor() {
this.pricingModel = {
storagePerGBPerEpoch: 0.001,
writeFeePerMB: 0.0001,
readFeePerMB: 0.00001,
gasMultiplier: 1.0
};
}
async analyzeCosts(timeRange: number = 30 * 24 * 60 * 60 * 1000): Promise<CostAnalysis> {
const records = this.getRelevantCostRecords(timeRange);
const storageMetrics = await this.getStorageMetrics(timeRange);
return {
totalCost: this.calculateTotalCost(records),
storageCost: this.calculateStorageCost(storageMetrics),
transactionCost: this.calculateTransactionCost(records),
breakdown: this.getCostBreakdown(records),
optimization: this.getOptimizationSuggestions(storageMetrics, records),
forecast: this.forecastCosts(records, storageMetrics)
};
}
private calculateStorageCost(metrics: StorageMetrics[]): number {
return metrics.reduce((total, metric) => {
const storageEpochs = 30; // 假设30天的轮数
const sizeGB = metric.totalSize / (1024 * 1024 * 1024);
return total + (sizeGB * this.pricingModel.storagePerGBPerEpoch * storageEpochs);
}, 0);
}
private calculateTransactionCost(records: CostRecord[]): number {
return records
.filter(r => r.type === 'transaction')
.reduce((total, record) => total + record.amount, 0);
}
private getOptimizationSuggestions(metrics: StorageMetrics[], records: CostRecord[]): OptimizationSuggestion[] {
const suggestions: OptimizationSuggestion[] = [];
// 分析文件大小分布
const sizeDistribution = this.analyzeSizeDistribution(metrics);
if (sizeDistribution.smallFiles > sizeDistribution.largeFiles * 2) {
suggestions.push({
type: 'BUNDLE_SMALL_FILES',
description: '检测到大量小文件,建议使用 Quilt 打包存储',
potentialSavings: '20-30%',
difficulty: 'medium',
implementation: this.getBundleImplementation()
});
}
// 分析存储时长
const avgStorageTime = this.calculateAverageStorageTime(metrics);
if (avgStorageTime > 90) { // 超过90天
suggestions.push({
type: 'OPTIMIZE_STORAGE_DURATION',
description: `平均存储时长 ${avgStorageTime} 天,建议实施生命周期管理`,
potentialSavings: '40-60%',
difficulty: 'low',
implementation: this.getLifecycleImplementation()
});
}
// 分析访问模式
const accessPattern = this.analyzeAccessPattern(records);
if (accessPattern.readHeavy) {
suggestions.push({
type: 'IMPLEMENT_CACHING',
description: '读取频繁,建议实施缓存层',
potentialSavings: '50-70%',
difficulty: 'medium',
implementation: this.getCacheImplementation()
});
}
return suggestions;
}
private getBundleImplementation(): string {
return `
// 使用 Quilt 打包小文件
async function bundleSmallFiles(files: WalrusFile[]): Promise<string> {
const quilt = QuiltBuilder.create()
.addFiles(files)
.build();
const result = await client.walrus.writeFiles({
files: [quilt],
epochs: 30,
deletable: true,
signer: keypair
});
return result[0].blobId;
}
// 原本多个小文件:
// File 1: 10KB, File 2: 15KB, File 3: 8KB = 33KB 总计
// 打包后:单个 Quilt 包含所有文件,减少存储开销
`;
}
private getLifecycleImplementation(): string {
return `
// 自动生命周期管理
class StorageLifecycleManager {
async manageExpiredFiles() {
const expiringFiles = await this.getFilesExpiringWithin(7);
for (const file of expiringFiles) {
const accessFrequency = await this.getAccessFrequency(file.blobId);
if (accessFrequency === 'never') {
// 删除未访问的文件
await this.deleteFile(file.blobId);
} else if (accessFrequency === 'rare') {
// 降低存储时长
await this.reduceStorageEpochs(file.blobId, 10);
} else {
// 续期重要文件
await this.extendStorage(file.blobId, 30);
}
}
}
private async getAccessFrequency(blobId: string): Promise<'never' | 'rare' | 'frequent'> {
// 分析访问日志
const accessLogs = await this.getAccessLogs(blobId, 30); // 30天内
const accessCount = accessLogs.length;
if (accessCount === 0) return 'never';
if (accessCount < 5) return 'rare';
return 'frequent';
}
}
`;
}
}
```
### 3. 性能监控
#### 实时性能指标
```typescript
class PerformanceMonitor {
private performanceMetrics: PerformanceMetric[] = [];
private slowQueries: SlowQuery[] = [];
private alerts: PerformanceAlert[] = [];
async recordPerformanceMetric(
operation: string,
duration: number,
success: boolean,
metadata: any = {}
): Promise<void> {
const metric: PerformanceMetric = {
timestamp: Date.now(),
operation,
duration,
success,
metadata
};
this.performanceMetrics.push(metric);
// 限制历史数据
if (this.performanceMetrics.length > 10000) {
this.performanceMetrics.shift();
}
// 检查性能告警
this.checkPerformanceAlerts(metric);
// 记录慢操作
if (duration > this.getSlowThreshold(operation)) {
this.slowQueries.push({
...metric,
threshold: this.getSlowThreshold(operation),
severity: this.getSeverityLevel(duration, this.getSlowThreshold(operation))
});
// 限制慢查询记录
if (this.slowQueries.length > 1000) {
this.slowQueries.shift();
}
}
}
getPerformanceAnalysis(timeRange: number = 24 * 60 * 60 * 1000): PerformanceAnalysis {
const metrics = this.getRelevantMetrics(timeRange);
return {
overview: this.getPerformanceOverview(metrics),
operations: this.analyzeOperations(metrics),
trends: this.analyzeTrends(metrics),
bottlenecks: this.identifyBottlenecks(metrics),
recommendations: this.getPerformanceRecommendations(metrics)
};
}
private analyzeOperations(metrics: PerformanceMetric[]): OperationAnalysis[] {
const operationGroups = this.groupBy(metrics, 'operation');
const analyses: OperationAnalysis[] = [];
for (const [operation, operationMetrics] of Object.entries(operationGroups)) {
const durations = operationMetrics.map(m => m.duration);
const successRate = operationMetrics.filter(m => m.success).length / operationMetrics.length;
analyses.push({
operation,
totalCalls: operationMetrics.length,
successRate,
avgDuration: durations.reduce((a, b) => a + b, 0) / durations.length,
minDuration: Math.min(...durations),
maxDuration: Math.max(...durations),
p95: this.percentile(durations, 0.95),
p99: this.percentile(durations, 0.99),
errorRate: 1 - successRate,
slowQueries: operationMetrics.filter(m => m.duration > this.getSlowThreshold(operation)).length
});
}
return analyses.sort((a, b) => b.avgDuration - a.avgDuration);
}
private identifyBottlenecks(metrics: PerformanceMetric[]): PerformanceBottleneck[] {
const bottlenecks: PerformanceBottleneck[] = [];
// 识别慢操作
const slowOperations = this.analyzeOperations(metrics)
.filter(op => op.avgDuration > this.getSlowThreshold(op.operation));
for (const operation of slowOperations) {
bottlenecks.push({
type: 'SLOW_OPERATION',
operation: operation.operation,
severity: this.getBottleneckSeverity(operation.avgDuration, this.getSlowThreshold(operation.operation)),
impact: 'medium',
description: `\${operation.operation} 平均耗时 \${operation.avgDuration}ms`,
suggestion: this.getOptimizationSuggestion(operation.operation)
});
}
// 识别错误率高的操作
const highErrorOps = this.analyzeOperations(metrics)
.filter(op => op.errorRate > 0.05); // 5% 错误率
for (const operation of highErrorOps) {
bottlenecks.push({
type: 'HIGH_ERROR_RATE',
operation: operation.operation,
severity: 'high',
impact: 'high',
description: `\${operation.operation} 错误率 \${(operation.errorRate * 100).toFixed(1)}%`,
suggestion: this.getErrorOptimizationSuggestion(operation.operation)
});
}
return bottlenecks;
}
private getPerformanceRecommendations(metrics: PerformanceMetric[]): PerformanceRecommendation[] {
const recommendations: PerformanceRecommendation[] = [];
// 分析上传性能
const uploadMetrics = metrics.filter(m => m.operation.startsWith('upload'));
if (uploadMetrics.length > 0) {
const avgUploadSize = this.getAverageUploadSize(uploadMetrics);
const avgUploadTime = uploadMetrics.reduce((sum, m) => sum + m.duration, 0) / uploadMetrics.length;
if (avgUploadSize > 10 * 1024 * 1024 && avgUploadTime > 10000) { // 10MB, 10s
recommendations.push({
type: 'UPLOAD_OPTIMIZATION',
priority: 'high',
title: '大文件上传优化',
description: '检测到大文件上传性能问题',
implementation: `
// 实施分块上传和断点续传
class ChunkedUploader {
async uploadLargeFile(file: File, chunkSize = 5 * 1024 * 1024): Promise<string> {
const chunks = Math.ceil(file.size / chunkSize);
const chunkIds: string[] = [];
for (let i = 0; i < chunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const chunk = file.slice(start, end);
const result = await this.uploadChunk(chunk, i, chunks);
chunkIds.push(result.blobId);
// 更新进度
this.updateProgress((i + 1) / chunks);
}
// 创建文件清单
return await this.createManifest(chunkIds, file);
}
}
// 使用压缩减少传输量
const compressedFile = await this.compressFile(file);
const uploadResult = await client.walrus.writeFiles({
files: [compressedFile],
epochs: 10,
signer: keypair
});
`,
expectedImprovement: '50-70%'
});
}
}
// 分析批量操作性能
const batchMetrics = metrics.filter(m => m.operation.includes('batch'));
if (batchMetrics.length > 0) {
const concurrencyIssues = batchMetrics.filter(m => m.duration > 60000).length; // 超过1分钟
if (concurrencyIssues > batchMetrics.length * 0.3) { // 30%超时
recommendations.push({
type: 'BATCH_OPTIMIZATION',
priority: 'medium',
title: '批量操作并发优化',
description: '批量操作存在并发瓶颈',
implementation: `
// 优化并发控制
class OptimizedBatchProcessor {
private readonly MAX_CONCURRENT = 3;
private readonly RETRY_DELAY = 1000;
async processBatch<T>(items: T[], processor: (item: T) => Promise<any>): Promise<any[]> {
const results: any[] = [];
const chunks = this.chunkArray(items, this.MAX_CONCURRENT);
for (const chunk of chunks) {
const chunkPromises = chunk.map(async (item, index) => {
try {
return await this.withRetry(() => processor(item), 3);
} catch (error) {
console.error(\`Batch item failed: \${error.message}\`);
return null;
}
});
const chunkResults = await Promise.all(chunkPromises);
results.push(...chunkResults);
// 批次间延迟
if (chunks.indexOf(chunk) < chunks.length - 1) {
await this.delay(this.RETRY_DELAY);
}
}
return results;
}
}
`,
expectedImprovement: '30-50%'
});
}
}
return recommendations;
}
}
```
### 4. 错误监控
#### 错误统计和分析
```typescript
class ErrorMonitor {
private errorLog: ErrorRecord[] = [];
private errorPatterns: ErrorPattern[] = [];
recordError(error: Error, context: ErrorContext): void {
const errorRecord: ErrorRecord = {
timestamp: Date.now(),
message: error.message,
stack: error.stack,
type: this.classifyError(error),
severity: this.determineSeverity(error, context),
context,
resolved: false
};
this.errorLog.push(errorRecord);
// 分析错误模式
this.analyzeErrorPattern(errorRecord);
// 错误告警
this.checkErrorAlerts(errorRecord);
}
getErrorAnalysis(timeRange: number = 24 * 60 * 60 * 1000): ErrorAnalysis {
const recentErrors = this.getRecentErrors(timeRange);
return {
summary: this.getErrorSummary(recentErrors),
trends: this.getErrorTrends(recentErrors),
patterns: this.getErrorPatterns(recentErrors),
recommendations: this.getErrorRecommendations(recentErrors),
resolutionRate: this.calculateResolutionRate(recentErrors)
};
}
private analyzeErrorPattern(errorRecord: ErrorRecord): void {
const patternKey = this.getPatternKey(errorRecord);
let pattern = this.errorPatterns.find(p => p.key === patternKey);
if (!pattern) {
pattern = {
key: patternKey,
type: errorRecord.type,
count: 0,
firstOccurrence: errorRecord.timestamp,
lastOccurrence: errorRecord.timestamp,
contexts: [],
resolutions: []
};
this.errorPatterns.push(pattern);
}
pattern.count++;
pattern.lastOccurrence = errorRecord.timestamp;
// 记录上下文
const contextHash = this.hashContext(errorRecord.context);
if (!pattern.contexts.some(c => c.hash === contextHash)) {
pattern.contexts.push({
hash: contextHash,
context: errorRecord.context,
occurrences: 1
});
} else {
const existingContext = pattern.contexts.find(c => c.hash === contextHash);
if (existingContext) {
existingContext.occurrences++;
}
}
}
private getErrorRecommendations(errors: ErrorRecord[]): ErrorRecommendation[] {
const recommendations: ErrorRecommendation[] = [];
// 分析最常见的错误类型
const errorTypes = this.groupBy(errors, 'type');
const mostCommonType = Object.entries(errorTypes)
.sort(([, a], [, b]) => b.length - a.length)[0];
if (mostCommonType && mostCommonType[1].length > errors.length * 0.3) { // 30%以上
recommendations.push({
type: 'PREVENTION',
priority: 'high',
title: `高频率 \${mostCommonType[0]} 错误`,
description: `\${mostCommonType[1].length} 次错误中 \${mostCommonType[1].length} 次是 \${mostCommonType[0]} 错误`,
implementation: this.getPreventionImplementation(mostCommonType[0]),
expectedReduction: '60-80%'
});
}
// 分析网络相关错误
const networkErrors = errors.filter(e => e.type === 'network' || e.type === 'timeout');
if (networkErrors.length > errors.length * 0.2) { // 20%以上
recommendations.push({
type: 'NETWORK_OPTIMIZATION',
priority: 'medium',
title: '网络连接优化',
description: '检测到大量网络相关错误',
implementation: `
// 实施网络优化策略
class NetworkOptimizer {
private readonly circuitBreaker = new CircuitBreaker({
failureThreshold: 5,
recoveryTimeout: 60000,
monitoringPeriod: 30000
});
async robustRequest(url: string, options: RequestInit = {}): Promise<Response> {
return this.circuitBreaker.execute(async () => {
// 使用指数退避重试
return this.withRetry(() => fetch(url, {
...options,
timeout: 30000
}), 3);
});
}
private async withRetry<T>(
operation: () => Promise<T>,
maxRetries: number = 3
): Promise<T> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
if (attempt === maxRetries || !this.isRetryableError(error)) {
throw error;
}
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
await this.delay(delay);
}
}
throw new Error('Max retries exceeded');
}
}
`,
expectedReduction: '70-90%'
});
}
return recommendations;
}
}
```
## 使用方法
### 存储使用监控
```typescript
skill: "walrus-monitor"
// monitor-type: usage
// time-range: 7d
// metrics: ["total-size", "file-count", "cost", "aging"]
```
### 成本分析
```typescript
skill: "walrus-monitor"
// monitor-type: cost
// time-range: 30d
// metrics: ["storage-cost", "transaction-cost", "optimization-suggestions"]
```
### 性能监控
```typescript
skill: "walrus-monitor"
// monitor-type: performance
// time-range: 24h
// metrics: ["upload-speed", "download-speed", "error-rate", "bottlenecks"]
```
### 错误分析
```typescript
skill: "walrus-monitor"
// monitor-type: errors
// time-range: 7d
// metrics: ["error-patterns", "resolution-rate", "prevention-suggestions"]
```
---
*更新时间2025-11-11*

View File

@@ -0,0 +1,761 @@
---
name: walrus-performance-optimizer
description: Walrus 性能优化专家 - 分析和优化 Walrus 应用的性能瓶颈
parameters:
- name: analysis-type
type: string
description: 分析类型 (upload/download/batch/memory/network)
required: true
- name: target-metric
type: string
description: 目标指标 (speed/throughput/cost/latency)
default: speed
- name: code-context
type: string
description: 代码上下文或问题描述
required: true
---
# Walrus 性能优化技能
## 技能概述
`walrus-performance-optimizer` 是专业的性能优化助手,专门分析 Walrus 应用的性能瓶颈,提供数据驱动的优化建议和具体的实施方案。
## 性能分析维度
### 1. 上传性能优化
#### 批量操作优化
```typescript
// 优化前:逐个上传文件
async function uploadFilesSlow(files: File[]) {
const results = [];
for (const file of files) {
const result = await uploadSingleFile(file);
results.push(result);
}
return results;
}
// 优化后:批量并发上传
class OptimizedUploader {
private readonly MAX_CONCURRENT = 5;
private readonly BATCH_DELAY = 100;
async uploadFilesOptimized(files: File[]): Promise<UploadResult[]> {
const results: UploadResult[] = [];
const chunks = this.chunkArray(files, this.MAX_CONCURRENT);
for (const chunk of chunks) {
const chunkPromises = chunk.map(file => this.uploadWithRetry(file));
const chunkResults = await Promise.allSettled(chunkPromises);
results.push(...this.processChunkResults(chunkResults));
// 批次间延迟,避免过载
if (chunks.indexOf(chunk) < chunks.length - 1) {
await this.delay(this.BATCH_DELAY);
}
}
return results;
}
private async uploadWithRetry(file: File, maxRetries = 3): Promise<UploadResult> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await this.uploadSingleFile(file);
} catch (error) {
if (attempt === maxRetries || !this.isRetryableError(error)) {
throw error;
}
// 指数退避
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
await this.delay(delay);
}
}
}
private chunkArray<T>(array: T[], size: number): T[][] {
const chunks: T[][] = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
}
private isRetryableError(error: any): boolean {
return error instanceof RetryableWalrusClientError ||
error.message.includes('timeout') ||
error.message.includes('network');
}
}
```
#### 文件压缩优化
```typescript
class CompressionOptimizer {
async optimizeUpload(file: File): Promise<OptimizedFile> {
const fileBuffer = await file.arrayBuffer();
const originalSize = fileBuffer.byteLength;
// 文本文件压缩
if (this.isTextFile(file)) {
const compressed = await this.compressText(fileBuffer);
if (compressed.size < originalSize * 0.8) {
return {
data: compressed.data,
originalSize,
compressedSize: compressed.size,
compressionRatio: compressed.size / originalSize,
method: 'gzip'
};
}
}
// 图片文件优化
if (this.isImageFile(file)) {
const optimized = await this.optimizeImage(fileBuffer);
if (optimized.size < originalSize * 0.9) {
return {
data: optimized.data,
originalSize,
compressedSize: optimized.size,
compressionRatio: optimized.size / originalSize,
method: 'image-optimization'
};
}
}
return {
data: new Uint8Array(fileBuffer),
originalSize,
compressedSize: originalSize,
compressionRatio: 1,
method: 'none'
};
}
private async compressText(data: ArrayBuffer): Promise<CompressedData> {
const compressionStream = new CompressionStream('gzip');
const writer = compressionStream.writable.getWriter();
const reader = compressionStream.readable.getReader();
writer.write(new Uint8Array(data));
writer.close();
const chunks: Uint8Array[] = [];
let totalSize = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
totalSize += value.length;
}
const combined = new Uint8Array(totalSize);
let offset = 0;
for (const chunk of chunks) {
combined.set(chunk, offset);
offset += chunk.length;
}
return { data: combined, size: totalSize };
}
private async optimizeImage(data: ArrayBuffer): Promise<CompressedData> {
// 使用 WebAssembly 进行图片优化
// 这里可以集成像 sharp.js 或其他图片处理库
const blob = new Blob([data], { type: 'image/jpeg' });
return new Promise((resolve) => {
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d')!;
// 降低质量但保持合理尺寸
const scale = Math.min(1, 1920 / Math.max(img.width, img.height));
canvas.width = img.width * scale;
canvas.height = img.height * scale;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
canvas.toBlob((blob) => {
if (blob) {
blob.arrayBuffer().then(buffer => {
const data = new Uint8Array(buffer);
resolve({ data, size: data.length });
});
}
}, 'image/jpeg', 0.85);
};
img.src = URL.createObjectURL(blob);
});
}
}
```
### 2. 下载性能优化
#### 智能缓存系统
```typescript
class IntelligentCache {
private cache = new Map<string, CacheEntry>();
private accessOrder = new Map<string, number>();
private accessCounter = 0;
private readonly MAX_SIZE = 100; // 最大缓存条目
private readonly TTL = 300000; // 5分钟过期
async get(blobId: string): Promise<Uint8Array | null> {
const entry = this.cache.get(blobId);
if (!entry) {
return null;
}
// 检查是否过期
if (Date.now() - entry.timestamp > this.TTL) {
this.delete(blobId);
return null;
}
// 更新访问顺序 (LRU)
this.accessOrder.set(blobId, ++this.accessCounter);
return entry.data;
}
async set(blobId: string, data: Uint8Array): Promise<void> {
// 检查缓存大小,必要时清理
if (this.cache.size >= this.MAX_SIZE) {
this.evictLRU();
}
this.cache.set(blobId, {
data,
timestamp: Date.now(),
size: data.length
});
this.accessOrder.set(blobId, ++this.accessCounter);
}
private evictLRU(): void {
let oldestKey = '';
let oldestAccess = Infinity;
for (const [key, accessTime] of this.accessOrder) {
if (accessTime < oldestAccess) {
oldestAccess = accessTime;
oldestKey = key;
}
}
if (oldestKey) {
this.delete(oldestKey);
}
}
private delete(blobId: string): void {
this.cache.delete(blobId);
this.accessOrder.delete(blobId);
}
getStats(): CacheStats {
return {
size: this.cache.size,
totalMemoryUsage: Array.from(this.cache.values())
.reduce((sum, entry) => sum + entry.size, 0),
hitRate: this.hitRate,
evictions: this.evictions
};
}
}
```
#### 预加载策略
```typescript
class PreloadingStrategy {
private preloadQueue = new Set<string>();
private preloadCache = new Map<string, PreloadEntry>();
async preloadFiles(blobIds: string[], priority: 'high' | 'medium' | 'low' = 'medium') {
const delay = priority === 'high' ? 0 : priority === 'medium' ? 100 : 500;
for (const blobId of blobIds) {
if (!this.preloadQueue.has(blobId)) {
this.preloadQueue.add(blobId);
// 延迟执行,避免阻塞主要操作
setTimeout(() => this.preloadFile(blobId), delay);
}
}
}
private async preloadFile(blobId: string) {
try {
const startTime = Date.now();
// 使用低优先级下载
const [file] = await client.walrus.getFiles({
ids: [blobId],
options: { priority: 'low' }
});
const content = await file.bytes();
const loadTime = Date.now() - startTime;
this.preloadCache.set(blobId, {
data: content,
timestamp: Date.now(),
loadTime
});
console.log(`预加载完成: ${blobId} (${loadTime}ms)`);
} catch (error) {
console.warn(`预加载失败: ${blobId}`, error.message);
} finally {
this.preloadQueue.delete(blobId);
}
}
async getPreloaded(blobId: string): Promise<Uint8Array | null> {
const entry = this.preloadCache.get(blobId);
if (!entry) {
return null;
}
// 检查是否过期
if (Date.now() - entry.timestamp > 600000) { // 10分钟
this.preloadCache.delete(blobId);
return null;
}
return entry.data;
}
}
```
### 3. 网络性能优化
#### 连接池管理
```typescript
class ConnectionPool {
private connections: Map<string, Connection[]> = new Map();
private readonly MAX_CONNECTIONS_PER_HOST = 5;
private readonly CONNECTION_TIMEOUT = 30000;
async getConnection(host: string): Promise<Connection> {
const pool = this.connections.get(host) || [];
// 尝试复用现有连接
for (const conn of pool) {
if (!conn.inUse && this.isConnectionHealthy(conn)) {
conn.inUse = true;
conn.lastUsed = Date.now();
return conn;
}
}
// 创建新连接
if (pool.length < this.MAX_CONNECTIONS_PER_HOST) {
const newConn = await this.createConnection(host);
newConn.inUse = true;
pool.push(newConn);
this.connections.set(host, pool);
return newConn;
}
// 等待连接可用
return this.waitForAvailableConnection(host);
}
releaseConnection(connection: Connection) {
connection.inUse = false;
connection.lastUsed = Date.now();
}
private async createConnection(host: string): Promise<Connection> {
return new Promise((resolve, reject) => {
const ws = new WebSocket(host);
const timeout = setTimeout(() => {
reject(new Error('Connection timeout'));
}, this.CONNECTION_TIMEOUT);
ws.onopen = () => {
clearTimeout(timeout);
resolve({
socket: ws,
created: Date.now(),
lastUsed: Date.now(),
inUse: true
});
};
ws.onerror = () => {
clearTimeout(timeout);
reject(new Error('Connection failed'));
};
});
}
private isConnectionHealthy(conn: Connection): boolean {
return conn.socket.readyState === WebSocket.OPEN &&
Date.now() - conn.lastUsed < 300000; // 5分钟未使用则关闭
}
private async waitForAvailableConnection(host: string): Promise<Connection> {
const pool = this.connections.get(host) || [];
return new Promise((resolve) => {
const checkInterval = setInterval(() => {
const available = pool.find(conn => !conn.inUse && this.isConnectionHealthy(conn));
if (available) {
clearInterval(checkInterval);
available.inUse = true;
available.lastUsed = Date.now();
resolve(available);
}
}, 100);
});
}
}
```
#### 请求优化
```typescript
class RequestOptimizer {
private pendingRequests = new Map<string, Promise<any>>();
private requestQueue: QueuedRequest[] = [];
private processing = false;
async batchRequest<T>(requests: BatchRequest[]): Promise<T[]> {
// 合并相同的请求
const uniqueRequests = this.deduplicateRequests(requests);
// 按优先级排序
uniqueRequests.sort((a, b) => b.priority - a.priority);
const results: T[] = [];
for (const request of uniqueRequests) {
try {
const result = await this.executeRequest(request);
results.push(result);
} catch (error) {
console.error(`批量请求失败: ${request.id}`, error);
results.push(null as T);
}
}
return results;
}
private deduplicateRequests(requests: BatchRequest[]): BatchRequest[] {
const seen = new Set<string>();
return requests.filter(req => {
const key = this.getRequestKey(req);
if (seen.has(key)) {
return false;
}
seen.add(key);
return true;
});
}
private async executeRequest(request: BatchRequest): Promise<any> {
const key = this.getRequestKey(request);
// 检查是否有相同请求正在进行
if (this.pendingRequests.has(key)) {
return await this.pendingRequests.get(key);
}
const requestPromise = this.performRequest(request);
this.pendingRequests.set(key, requestPromise);
try {
const result = await requestPromise;
return result;
} finally {
this.pendingRequests.delete(key);
}
}
private async performRequest(request: BatchRequest): Promise<any> {
// 实现实际的请求逻辑
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), request.timeout);
try {
const response = await fetch(request.url, {
...request.options,
signal: controller.signal
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} finally {
clearTimeout(timeoutId);
}
}
}
```
### 4. 内存优化
#### 内存池管理
```typescript
class MemoryPool {
private pools = new Map<number, ArrayBuffer[]>();
private readonly MAX_POOL_SIZE = 50;
private readonly ALLOC_INCREMENT = 1024; // 1KB increments
allocate(size: number): ArrayBuffer {
const actualSize = Math.ceil(size / this.ALLOC_INCREMENT) * this.ALLOC_INCREMENT;
const pool = this.pools.get(actualSize) || [];
if (pool.length > 0) {
return pool.pop()!;
}
return new ArrayBuffer(actualSize);
}
release(buffer: ArrayBuffer): void {
const size = buffer.byteLength;
const pool = this.pools.get(size) || [];
if (pool.length < this.MAX_POOL_SIZE) {
// 清零缓冲区(安全考虑)
new Uint8Array(buffer).fill(0);
pool.push(buffer);
this.pools.set(size, pool);
}
}
getStats(): MemoryPoolStats {
const stats: MemoryPoolStats = {
totalBuffers: 0,
totalMemory: 0,
poolSizes: {}
};
for (const [size, pool] of this.pools) {
stats.totalBuffers += pool.length;
stats.totalMemory += size * pool.length;
stats.poolSizes[size] = pool.length;
}
return stats;
}
}
```
#### 流式处理
```typescript
class StreamProcessor {
async processLargeFile(
file: File,
processor: (chunk: Uint8Array, index: number) => Promise<void>,
chunkSize = 1024 * 1024 // 1MB chunks
): Promise<void> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
let offset = 0;
let index = 0;
const processChunk = () => {
if (offset >= file.size) {
resolve();
return;
}
const chunk = file.slice(offset, offset + chunkSize);
reader.onload = async (event) => {
if (event.target?.result) {
const arrayBuffer = event.target.result as ArrayBuffer;
const uint8Array = new Uint8Array(arrayBuffer);
try {
await processor(uint8Array, index);
offset += chunkSize;
index++;
processChunk();
} catch (error) {
reject(error);
}
}
};
reader.readAsArrayBuffer(chunk);
};
processChunk();
});
}
async uploadStream(
file: File,
onProgress?: (progress: number) => void
): Promise<string> {
const chunks: Uint8Array[] = [];
const totalSize = file.size;
await this.processLargeFile(file, async (chunk, index) => {
chunks.push(chunk);
const progress = ((index + 1) * chunk.length) / totalSize;
onProgress?.(Math.min(progress, 1));
});
// 合并所有块
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
const combined = new Uint8Array(totalLength);
let offset = 0;
for (const chunk of chunks) {
combined.set(chunk, offset);
offset += chunk.length;
}
// 上传合并后的数据
const walrusFile = WalrusFile.from({
contents: combined,
identifier: `stream/${Date.now()}_${file.name}`
});
const result = await client.walrus.writeFiles({
files: [walrusFile],
epochs: 10,
deletable: true
});
return result[0].blobId;
}
}
```
## 性能监控
### 实时性能指标
```typescript
class PerformanceMonitor {
private metrics = new Map<string, MetricEntry[]>();
private readonly MAX_METRICS = 1000;
recordMetric(name: string, value: number, tags: Record<string, string> = {}) {
const entry: MetricEntry = {
timestamp: Date.now(),
value,
tags
};
const existing = this.metrics.get(name) || [];
existing.push(entry);
// 限制历史数据数量
if (existing.length > this.MAX_METRICS) {
existing.splice(0, existing.length - this.MAX_METRICS);
}
this.metrics.set(name, existing);
}
getMetrics(name: string, timeRange?: number): MetricEntry[] {
const allMetrics = this.metrics.get(name) || [];
if (!timeRange) {
return allMetrics;
}
const cutoff = Date.now() - timeRange;
return allMetrics.filter(m => m.timestamp >= cutoff);
}
getAggregatedMetrics(name: string, timeRange = 300000): AggregatedMetrics {
const metrics = this.getMetrics(name, timeRange);
if (metrics.length === 0) {
return {
count: 0,
sum: 0,
avg: 0,
min: 0,
max: 0,
p50: 0,
p95: 0,
p99: 0
};
}
const values = metrics.map(m => m.value).sort((a, b) => a - b);
const sum = values.reduce((s, v) => s + v, 0);
return {
count: values.length,
sum,
avg: sum / values.length,
min: values[0],
max: values[values.length - 1],
p50: this.percentile(values, 0.5),
p95: this.percentile(values, 0.95),
p99: this.percentile(values, 0.99)
};
}
private percentile(sorted: number[], p: number): number {
const index = Math.ceil(sorted.length * p) - 1;
return sorted[Math.max(0, index)];
}
}
```
## 使用方法
### 基础性能分析
```typescript
skill: "walrus-performance-optimizer"
// analysis-type: upload
// target-metric: speed
// code-context: 我的文件上传速度很慢单个10MB文件需要2分钟如何优化
```
### 批量操作优化
```typescript
skill: "walrus-performance-optimizer"
// analysis-type: batch
// target-metric: throughput
// code-context: 批量上传100个文件时经常超时需要优化并发处理
```
### 内存使用优化
```typescript
skill: "walrus-performance-optimizer"
// analysis-type: memory
// target-metric: cost
// code-context: 大文件处理时内存占用过高,浏览器经常崩溃
```
### 网络优化
```typescript
skill: "walrus-performance-optimizer"
// analysis-type: network
// target-metric: latency
// code-context: 网络不稳定环境下频繁上传失败,需要优化网络策略
```
---
*更新时间2025-11-11*