Skip to content

refactor: export progress #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/cli/src/commands/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class ExportCommand extends TelegramCommand {
}

private async promptForOptions(options: Partial<ExportOptions>): Promise<ExportOptions> {
const chats = await this.getClient().getChats()
const chats = await this.getClient().getDialogs()
logger.debug(`获取到 ${chats.length} 个会话`)

const chatChoices = chats.map((chat: DatabaseNewChat) => ({
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ async function selectTargetChat(client: any, sourceChatName: string): Promise<Se

// Get chat info to verify ID
logger.debug('正在验证会话...')
const chats = await client.getChats()
const chats = await client.getDialogs()
const selectedChat = chats.find((c: TelegramChat) => c.id === Number(chatId))
if (!selectedChat) {
throw new Error(`找不到会话: ${chatId}`)
Expand All @@ -382,7 +382,7 @@ async function selectTargetChat(client: any, sourceChatName: string): Promise<Se
default: false,
})) {
logger.debug('正在从 Telegram 获取会话列表...')
const telegramChats = await client.getChats()
const telegramChats = await client.getDialogs()
logger.debug(`从 Telegram 获取到 ${telegramChats.length} 个会话`)

// Update chats in database
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class SyncCommand extends TelegramCommand {

// Sync chats
logger.log('正在同步会话...')
const newChats = await this.getClient().getChats()
const newChats = await this.getClient().getDialogs()
logger.debug(`获取到 ${newChats.length} 个会话`)

for (const chat of newChats) {
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class WatchCommand extends TelegramCommand {

private async watchChat(chatId: number, folderTitle: string): Promise<number> {
// Get dialog info
const result = await this.getClient().getDialogs(0, 100)
const result = await this.getClient().getPaginationDialogs(0, 100)
const selectedDialog = result.chats.find((d: TelegramChat) => d.id === chatId)
if (!selectedDialog) {
logger.log('找不到该对话')
Expand Down Expand Up @@ -92,7 +92,7 @@ export class WatchCommand extends TelegramCommand {
})

// Get all chats in folder
const dialogs = await this.getClient().getDialogs()
const dialogs = await this.getClient().getPaginationDialogs()
logger.debug(`获取到 ${dialogs.chats.length} 个会话`)
const chatChoices = dialogs.chats.map((dialog: TelegramChat) => ({
name: `[${dialog.type}] ${dialog.title} (${dialog.unreadCount} 条未读)`,
Expand Down
21 changes: 17 additions & 4 deletions packages/core/src/adapter/client/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ export class ClientAdapter implements ITelegramClientAdapter {
await this.client.disconnect()
}

async getDialogs(offset = 0, limit = 10): Promise<TelegramChatsResult> {
return this.dialogManager.getDialogs(offset, limit)
async getPaginationDialogs(offset = 0, limit = 10): Promise<TelegramChatsResult> {
return this.dialogManager.getPaginationDialogs(offset, limit)
}

/**
Expand Down Expand Up @@ -442,6 +442,19 @@ export class ClientAdapter implements ITelegramClientAdapter {
}
}

async getHistory(chatId: number): Promise<Api.messages.TypeMessages & { count: number }> {
return this.client.invoke(new Api.messages.GetHistory({
peer: chatId,
limit: 1,
offsetId: 0,
offsetDate: 0,
addOffset: 0,
maxId: 0,
minId: 0,
hash: bigInt(0),
})) as Promise<Api.messages.TypeMessages & { count: number }>
}

onMessage(callback: (message: TelegramMessage) => Promise<void>) {
this.messageCallback = callback
}
Expand All @@ -454,7 +467,7 @@ export class ClientAdapter implements ITelegramClientAdapter {
return this.folderManager.getFoldersForChat(chatId)
}

async getChats(): Promise<DatabaseNewChat[]> {
return this.dialogManager.getChats()
async getDialogs(): Promise<DatabaseNewChat[]> {
return this.dialogManager.getDialogs()
}
}
4 changes: 2 additions & 2 deletions packages/core/src/adapter/client/dialog-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class DialogManager {
/**
* Get all dialogs (chats) with pagination
*/
async getDialogs(offset = 0, limit = 10): Promise<TelegramChatsResult> {
async getPaginationDialogs(offset = 0, limit = 10): Promise<TelegramChatsResult> {
// Get dialogs with pagination
const dialogs = await this.client.getDialogs({
limit: limit + 1, // Get one extra to check if there are more
Expand Down Expand Up @@ -56,7 +56,7 @@ export class DialogManager {
/**
* Get all chats from Telegram
*/
async getChats(): Promise<DatabaseNewChat[]> {
async getDialogs(): Promise<DatabaseNewChat[]> {
const chats: DatabaseNewChat[] = []

try {
Expand Down
12 changes: 9 additions & 3 deletions packages/core/src/services/export.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { DatabaseMessageType, DatabaseNewChat } from '@tg-search/db'
import type { DatabaseChatType, DatabaseMessageType } from '@tg-search/db'
import type { ITelegramClientAdapter } from '../types/adapter'
import type { TelegramMessage } from '../types/message'

Expand All @@ -23,7 +23,11 @@ export type ExportMethod = 'getMessage' | 'takeout'
* Export service options
*/
export interface ExportOptions {
chatMetadata: DatabaseNewChat
chatMetadata: {
id: number
title: string
type: DatabaseChatType
}
chatId: number
format?: ExportFormat
path?: string
Expand Down Expand Up @@ -132,11 +136,13 @@ export class ExportService {
// Report progress
onProgress?.(5, `已选择会话: ${chatMetadata.title}`)

const history = await this.client.getHistory(chatId)

// Export messages
let count = 0
let failedCount = 0
let messages: TelegramMessage[] = []
const total = limit || chatMetadata.messageCount || 100
const total = limit || history.count || 100

function isSkipMedia(type: DatabaseMessageType) {
return !messageTypes.includes(type)
Expand Down
10 changes: 8 additions & 2 deletions packages/core/src/types/adapter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { DatabaseFolder, DatabaseNewChat } from '@tg-search/db'
import type { Api } from 'telegram'
import type { TelegramChatsResult } from './chat'
import type { TelegramFolder } from './folder'
import type { GetTelegramMessageParams, TelegramMessage } from './message'
Expand Down Expand Up @@ -77,7 +78,7 @@ export interface ITelegramClientAdapter extends BaseTelegramAdapter {
/**
* Get all dialogs (chats) with pagination
*/
getDialogs: (offset?: number, limit?: number) => Promise<TelegramChatsResult>
getPaginationDialogs: (offset?: number, limit?: number) => Promise<TelegramChatsResult>

/**
* Get all folders from Telegram
Expand All @@ -87,10 +88,15 @@ export interface ITelegramClientAdapter extends BaseTelegramAdapter {
/**
* Get all chats from Telegram
*/
getChats: () => Promise<DatabaseNewChat[]>
getDialogs: () => Promise<DatabaseNewChat[]>

/**
* Get folders for a specific chat
*/
getFoldersForChat: (chatId: number) => Promise<TelegramFolder[]>

/**
* Get history for a specific chat
*/
getHistory: (chatId: number) => Promise<Api.messages.TypeMessages & { count: number }>
}
12 changes: 5 additions & 7 deletions packages/frontend/src/apis/commands/useExport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function useExport() {
...commandHandler
} = useCommandHandler()

const exportProgress = ref<string[]>([])
const exportProgress = ref<number>(0)
const lastExportParams = ref<ExportParams | null>(null)

async function executeExport(params: ExportParams) {
Expand All @@ -22,15 +22,13 @@ export function useExport() {
}

lastExportParams.value = params
exportProgress.value = []
exportProgress.value = 0

const options: SSEClientOptions<Command, Command> = {
onProgress: (data: Command | string) => {
if (typeof data === 'string') {
exportProgress.value.push(data)
}
else {
if (typeof data !== 'string') {
updateCommand(data)
exportProgress.value = data.progress
}
},
onComplete: updateCommand,
Expand All @@ -53,7 +51,7 @@ export function useExport() {

function cleanup() {
commandHandler.cleanup()
exportProgress.value = []
exportProgress.value = 0
lastExportParams.value = null
}

Expand Down
35 changes: 10 additions & 25 deletions packages/frontend/src/components/commands/ExportCommand.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ const props = defineProps<{
const {
executeExport,
currentCommand,
isLoading,
isConnected,
exportProgress,
cleanup,
} = useExport()

Expand Down Expand Up @@ -74,7 +73,7 @@ async function handleExport() {
return
}

const toastId = toast.loading('正在准备导出...')
const toastId = toast.loading('正在导出...')
const result = await executeExport({
chatId: selectedChatId.value,
messageTypes: selectedMessageTypes.value,
Expand All @@ -84,11 +83,13 @@ async function handleExport() {
if (!result.success) {
toast.error(result.error || '导出失败', { id: toastId })
}
else {
toast.success('导出成功', { id: toastId })
}
}

// Computed properties for progress display
const isExporting = computed(() => currentCommand.value?.status === 'running')
const exportProgress = computed(() => currentCommand.value?.progress || 0)
const exportStatus = computed(() => {
if (!currentCommand.value)
return ''
Expand Down Expand Up @@ -139,22 +140,6 @@ function formatTime(time: string): string {

<template>
<div class="space-y-4">
<!-- Connection status -->
<div
v-if="!isConnected"
class="flex items-center gap-2 rounded bg-yellow-100 p-4 text-yellow-800 dark:bg-yellow-800 dark:text-yellow-100"
>
<svg class="h-5 w-5 animate-spin" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none" />
<path
class="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
<span>正在连接命令服务...</span>
</div>

<!-- Export settings -->
<div class="rounded bg-white p-4 shadow dark:bg-gray-800 dark:text-gray-100">
<h2 class="mb-2 text-lg font-semibold">
Expand All @@ -169,7 +154,7 @@ function formatTime(time: string): string {
<select
v-model="selectedChatType"
class="w-full border border-gray-300 rounded bg-white p-2 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100"
:disabled="isLoading || isExporting"
:disabled="isExporting"
>
<option
v-for="option in chatTypeOptions"
Expand All @@ -189,7 +174,7 @@ function formatTime(time: string): string {
<select
v-model="selectedChatId"
class="w-full border border-gray-300 rounded bg-white p-2 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100"
:disabled="isLoading || isExporting"
:disabled="isExporting"
>
<option value="">
请选择会话
Expand Down Expand Up @@ -220,7 +205,7 @@ function formatTime(time: string): string {
type="checkbox"
:value="option.value"
class="border-gray-300 rounded text-blue-600 dark:border-gray-600 dark:bg-gray-700"
:disabled="isLoading || isExporting"
:disabled="isExporting"
>
<span class="ml-2">{{ option.label }}</span>
</label>
Expand All @@ -235,7 +220,7 @@ function formatTime(time: string): string {
<select
v-model="selectedMethod"
class="w-full border border-gray-300 rounded bg-white p-2 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100"
:disabled="isLoading || isExporting"
:disabled="isExporting"
>
<option
v-for="option in exportMethodOptions"
Expand All @@ -250,7 +235,7 @@ function formatTime(time: string): string {
<!-- Export button -->
<button
class="w-full rounded bg-blue-500 px-4 py-2 text-white dark:bg-blue-600 hover:bg-blue-600 disabled:opacity-50 dark:hover:bg-blue-700"
:disabled="isLoading || isExporting || !selectedChatId || selectedMessageTypes.length === 0"
:disabled="isExporting || !selectedChatId || selectedMessageTypes.length === 0"
@click="handleExport"
>
{{ isExporting ? '导出中...' : '开始导出' }}
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/routes/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function setupCommandRoutes(app: App) {
}

// Get chat metadata
const chats = await client.getChats()
const chats = await client.getDialogs()
const chat = chats.find(c => c.id === validatedBody.chatId)
if (!chat) {
throw new Error(`Chat ${validatedBody.chatId} not found`)
Expand Down