1+ using System ;
2+ using System . Diagnostics ;
3+ using System . IO ;
4+ using System . IO . Compression ;
5+ using System . Threading ;
6+
7+ namespace ChatCaster . Updater ;
8+
9+ class Program
10+ {
11+ private static string _logPath = "" ;
12+
13+ static int Main ( string [ ] args )
14+ {
15+ try
16+ {
17+ // Настраиваем логирование
18+ _logPath = Path . Combine ( Path . GetTempPath ( ) , "ChatCaster-updater.log" ) ;
19+
20+ Log ( "=== ChatCaster Updater запущен ===" ) ;
21+ Log ( $ "Аргументы: { string . Join ( " " , args ) } ") ;
22+
23+ // Проверяем аргументы
24+ if ( args . Length < 3 )
25+ {
26+ Log ( "ОШИБКА: Недостаточно аргументов" ) ;
27+ Log ( "Использование: ChatCaster.Updater.exe <путь_к_текущему_exe> <путь_к_ZIP_архиву> <перезапустить_true/false>" ) ;
28+ return 1 ;
29+ }
30+
31+ string currentExePath = args [ 0 ] ;
32+ string zipFilePath = args [ 1 ] ;
33+ bool restartApp = bool . Parse ( args [ 2 ] ) ;
34+
35+ Log ( $ "Текущий exe: { currentExePath } ") ;
36+ Log ( $ "ZIP архив: { zipFilePath } ") ;
37+ Log ( $ "Перезапуск: { restartApp } ") ;
38+
39+ // Ждем закрытия основного приложения
40+ Log ( "Ожидание закрытия основного приложения..." ) ;
41+ Thread . Sleep ( 3000 ) ;
42+
43+ // Принудительно завершаем процессы ChatCaster
44+ Log ( "Завершение процессов ChatCaster..." ) ;
45+ TerminateChatCasterProcesses ( ) ;
46+ Thread . Sleep ( 2000 ) ;
47+
48+ // Проверяем существование файлов
49+ if ( ! File . Exists ( zipFilePath ) )
50+ {
51+ Log ( $ "ОШИБКА: ZIP файл не найден: { zipFilePath } ") ;
52+ return 1 ;
53+ }
54+
55+ if ( ! File . Exists ( currentExePath ) )
56+ {
57+ Log ( $ "ОШИБКА: Текущий exe файл не найден: { currentExePath } ") ;
58+ return 1 ;
59+ }
60+
61+ // Получаем директорию приложения
62+ string appDirectory = Path . GetDirectoryName ( currentExePath ) ;
63+ if ( string . IsNullOrEmpty ( appDirectory ) )
64+ {
65+ Log ( "ОШИБКА: Не удалось определить директорию приложения" ) ;
66+ return 1 ;
67+ }
68+
69+ Log ( $ "Директория приложения: { appDirectory } ") ;
70+
71+ // Создаем временную папку для распаковки
72+ string tempExtractPath = Path . Combine ( Path . GetTempPath ( ) , "ChatCaster-Update-Extract" ) ;
73+ Log ( $ "Временная папка: { tempExtractPath } ") ;
74+
75+ // Удаляем старую временную папку если есть
76+ if ( Directory . Exists ( tempExtractPath ) )
77+ {
78+ Log ( "Удаление старой временной папки..." ) ;
79+ Directory . Delete ( tempExtractPath , true ) ;
80+ }
81+
82+ // Создаем временную папку
83+ Directory . CreateDirectory ( tempExtractPath ) ;
84+ Log ( "Временная папка создана" ) ;
85+
86+ // Распаковываем ZIP архив
87+ Log ( "Распаковка ZIP архива..." ) ;
88+ ZipFile . ExtractToDirectory ( zipFilePath , tempExtractPath ) ;
89+ Log ( "ZIP архив распакован успешно" ) ;
90+
91+ // Проверяем что распаковка прошла успешно
92+ var extractedFiles = Directory . GetFiles ( tempExtractPath , "*" , SearchOption . AllDirectories ) ;
93+ Log ( $ "Распаковано файлов: { extractedFiles . Length } ") ;
94+
95+ if ( extractedFiles . Length == 0 )
96+ {
97+ Log ( "ОШИБКА: ZIP архив пустой или не распаковался" ) ;
98+ return 1 ;
99+ }
100+
101+ // Создаем резервную копию основного exe файла
102+ string backupPath = currentExePath + ".backup" ;
103+ Log ( "Создание резервной копии..." ) ;
104+ File . Copy ( currentExePath , backupPath , true ) ;
105+ Log ( $ "Резервная копия создана: { backupPath } ") ;
106+
107+ // Копируем новые файлы
108+ Log ( "Копирование новых файлов..." ) ;
109+ CopyDirectory ( tempExtractPath , appDirectory ) ;
110+ Log ( "Файлы скопированы успешно" ) ;
111+
112+ // Проверяем что основной файл обновился
113+ if ( File . Exists ( currentExePath ) )
114+ {
115+ var newFileInfo = new FileInfo ( currentExePath ) ;
116+ Log ( $ "Основной файл обновлен успешно. Размер: { newFileInfo . Length } байт, Дата: { newFileInfo . LastWriteTime } ") ;
117+
118+ // Удаляем резервную копию
119+ File . Delete ( backupPath ) ;
120+ Log ( "Резервная копия удалена" ) ;
121+ }
122+ else
123+ {
124+ Log ( "КРИТИЧЕСКАЯ ОШИБКА: Основной файл не найден после копирования!" ) ;
125+
126+ // Восстанавливаем из резерва
127+ if ( File . Exists ( backupPath ) )
128+ {
129+ File . Copy ( backupPath , currentExePath , true ) ;
130+ File . Delete ( backupPath ) ;
131+ Log ( "Основной файл восстановлен из резервной копии" ) ;
132+ }
133+ return 1 ;
134+ }
135+
136+ // Запускаем приложение если нужно
137+ if ( restartApp )
138+ {
139+ Log ( "Запуск обновленного приложения..." ) ;
140+ var startInfo = new ProcessStartInfo
141+ {
142+ FileName = currentExePath ,
143+ UseShellExecute = true ,
144+ WorkingDirectory = appDirectory
145+ } ;
146+
147+ Process . Start ( startInfo ) ;
148+ Log ( "Приложение запущено успешно" ) ;
149+ }
150+
151+ // Очищаем временные файлы
152+ Log ( "Очистка временных файлов..." ) ;
153+ try
154+ {
155+ if ( Directory . Exists ( tempExtractPath ) )
156+ {
157+ Directory . Delete ( tempExtractPath , true ) ;
158+ }
159+
160+ if ( File . Exists ( zipFilePath ) )
161+ {
162+ File . Delete ( zipFilePath ) ;
163+ }
164+
165+ Log ( "Временные файлы удалены" ) ;
166+ }
167+ catch ( Exception ex )
168+ {
169+ Log ( $ "Предупреждение: Не удалось удалить временные файлы: { ex . Message } ") ;
170+ }
171+
172+ Log ( "=== Обновление завершено успешно ===" ) ;
173+ return 0 ;
174+ }
175+ catch ( Exception ex )
176+ {
177+ Log ( $ "КРИТИЧЕСКАЯ ОШИБКА: { ex . Message } ") ;
178+ Log ( $ "Stack trace: { ex . StackTrace } ") ;
179+ return 1 ;
180+ }
181+ }
182+
183+ private static void TerminateChatCasterProcesses ( )
184+ {
185+ try
186+ {
187+ var processes = Process . GetProcessesByName ( "ChatCaster.Windows" ) ;
188+ foreach ( var process in processes )
189+ {
190+ try
191+ {
192+ Log ( $ "Завершение процесса: PID { process . Id } ") ;
193+ process . Kill ( ) ;
194+ process . WaitForExit ( 5000 ) ;
195+ }
196+ catch ( Exception ex )
197+ {
198+ Log ( $ "Не удалось завершить процесс { process . Id } : { ex . Message } ") ;
199+ }
200+ }
201+ }
202+ catch ( Exception ex )
203+ {
204+ Log ( $ "Ошибка при завершении процессов: { ex . Message } ") ;
205+ }
206+ }
207+
208+ private static void CopyDirectory ( string sourceDir , string destinationDir )
209+ {
210+ var dir = new DirectoryInfo ( sourceDir ) ;
211+
212+ if ( ! dir . Exists )
213+ throw new DirectoryNotFoundException ( $ "Исходная директория не найдена: { sourceDir } ") ;
214+
215+ DirectoryInfo [ ] dirs = dir . GetDirectories ( ) ;
216+
217+ // Создаем целевую директорию если не существует
218+ Directory . CreateDirectory ( destinationDir ) ;
219+
220+ // Копируем файлы в текущей директории
221+ foreach ( FileInfo file in dir . GetFiles ( ) )
222+ {
223+ string targetFilePath = Path . Combine ( destinationDir , file . Name ) ;
224+ Log ( $ "Копирование файла: { file . Name } ") ;
225+ file . CopyTo ( targetFilePath , true ) ;
226+ }
227+
228+ // Рекурсивно копируем поддиректории
229+ foreach ( DirectoryInfo subDir in dirs )
230+ {
231+ string newDestinationDir = Path . Combine ( destinationDir , subDir . Name ) ;
232+ Log ( $ "Копирование директории: { subDir . Name } ") ;
233+ CopyDirectory ( subDir . FullName , newDestinationDir ) ;
234+ }
235+ }
236+
237+ private static void Log ( string message )
238+ {
239+ string logMessage = $ "[{ DateTime . Now : yyyy-MM-dd HH:mm:ss.fff} ] { message } ";
240+ Console . WriteLine ( logMessage ) ;
241+
242+ try
243+ {
244+ File . AppendAllText ( _logPath , logMessage + Environment . NewLine ) ;
245+ }
246+ catch
247+ {
248+ // Игнорируем ошибки записи в лог
249+ }
250+ }
251+ }
0 commit comments