SlnDmry commited on
Commit
22c2466
·
verified ·
1 Parent(s): ae4c264

Update bot.js

Browse files
Files changed (1) hide show
  1. bot.js +198 -134
bot.js CHANGED
@@ -27,16 +27,22 @@ let viewerTimeout = null;
27
  let bot = null;
28
  let botIsReady = false;
29
  let baglantiTuru = "Yok";
30
- let activeMessages = []; // Canlı mesajların tutulacağı dizi
31
- let messagesTimeout = null; // 1 dakikalık kapatma sayacı
32
  const ansiToHtmlConvert = new (require('ansi-to-html'))({ newline: true });
33
 
34
- // --- GARANTİ BAĞLANTI VE SOKET KONTROLÜ İÇİN GLOBAL DEĞİŞKENLER ---
35
- let isConnecting = false; // Çift tünel açılmasını engelleyen kesin kilit (State)
36
- let reconnectTimeout = null; // Çakışan mükerrer timeout'ları temizlemek için global referans
37
- let currentSshClient = null; // Aktif SSH nesnesinin imhası için global referans
38
- let currentStream = null; // Aktif Tünel stream imhası için global referans
39
- let currentSocket = null; // Aktif Normal TCP soket imhası için global referans
 
 
 
 
 
 
40
 
41
  // Dış IP tespiti
42
  https.get('https://api.ipify.org?format=json', (res) => {
@@ -46,89 +52,26 @@ https.get('https://api.ipify.org?format=json', (res) => {
46
  try {
47
  const ipInfo = JSON.parse(data);
48
  console.log(`Dış IP adresin: ${ipInfo.ip}`);
49
- } catch (err) {
50
- console.error('JSON parse hatası:', err);
51
- }
52
  });
53
- }).on('error', (err) => {
54
- console.error('İstek hatası:', err);
55
- });
56
 
57
  async function createBot() {
58
- // MÜKERRER BAĞLANTI ENGELLEME: Eğer zaten bir bağlantı süreci aktifse fonksiyonu anında durdur.
59
  if (isConnecting) {
60
  logger.warn("[Sistem] Zaten aktif bir bağlantı süreci yürütülüyor. Mükerrer istek engellendi.");
61
  return;
62
  }
63
- isConnecting = true; // Kilidi kapat
 
64
 
65
  const net = require('net');
66
  const sshClient = new Client();
67
- currentSshClient = sshClient; // Global referansa eşitle
68
-
69
- // --- GİTHUB CONFIG ÇEKME AŞAMASI (DİNAMİK SSH) ---
70
- const githubRawUrl = 'https://raw.githubusercontent.com/suvarileader/che/refs/heads/main/doc/ower/doc.json';
71
- logger.info("[GitHub Config] Güncel SSH tünel bilgileri GitHub'dan çekiliyor...");
72
-
73
- let remoteData = null;
74
- try {
75
- remoteData = await new Promise((resolve, reject) => {
76
- https.get(githubRawUrl, (res) => {
77
- let body = '';
78
- res.on('data', chunk => body += chunk);
79
- res.on('end', () => {
80
- try {
81
- resolve(JSON.parse(body));
82
- } catch (e) {
83
- reject(new Error("JSON Ayrıştırma Hatası: " + e.message));
84
- }
85
- });
86
- }).on('error', (err) => reject(err));
87
- });
88
- logger.info("[GitHub Config] SSH dosyası başarıyla indirildi.");
89
- } catch (err) {
90
- logger.error(`[GitHub Config Hatası] SSH verisi alınamadı: ${err.message}. Sabit SSH ayarlarıyla devam ediliyor...`);
91
- }
92
-
93
- // Varsayılan / Sabit SSH Ayarları (Yedek)
94
- let sshConfig = {
95
- host: 'tr1.vpnjantit.com',
96
- port: 22,
97
- username: 'suvaa-vpnjantit.com',
98
- password: 'suvaa'
99
- };
100
-
101
- // Yerel config'den bot kullanıcı adı
102
- const currentBotUsername = config["bot-account"]["username"];
103
 
104
- // GitHub'dan gelen verilerle SSH konfigürasyonunu eşleştirme
105
- if (remoteData && Array.isArray(remoteData)) {
106
- const myConfig = remoteData.find(item => item.account === currentBotUsername);
107
- if (myConfig) {
108
- logger.info(`[GitHub Config] '${currentBotUsername}' botu için dinamik SSH parametreleri uygulandı.`);
109
- if (myConfig.serverName && myConfig.serverName !== "empty") {
110
- sshConfig.host = myConfig.serverName;
111
- }
112
- if (myConfig.username && myConfig.username !== "empty") {
113
- sshConfig.username = myConfig.username;
114
- }
115
-
116
- // SSH Şifre ataması
117
- if (myConfig.pass && myConfig.pass !== "empty") {
118
- sshConfig.password = myConfig.pass;
119
- } else {
120
- sshConfig.password = config.utils["auto-auth"].password;
121
- }
122
- } else {
123
- logger.warn(`[GitHub Config] Listede '${currentBotUsername}' bulunamadı. Sabit/Yedek SSH kullanılacak.`);
124
- }
125
- }
126
-
127
- // Minecraft Sunucu Hedef Bilgileri (Yerel config'den)
128
  const targetServerIp = config.server.ip;
129
  const targetServerPort = config.server.port;
 
130
 
131
- // Mineflayer Başlatılıyor
132
  bot = mineflayer.createBot({
133
  username: currentBotUsername,
134
  auth: config["bot-account"]["type"],
@@ -136,70 +79,141 @@ async function createBot() {
136
  port: targetServerPort,
137
  version: config.server.version,
138
 
139
- connect: (client) => {
140
  let fallbackTriggered = false;
141
  let isFinalFailureHandled = false;
142
 
143
- // Kritik Çökme Yönetim Merkezi
144
  const handleFinalFailure = (reason) => {
145
  if (isFinalFailureHandled) return;
146
  isFinalFailureHandled = true;
147
 
148
- logger.error(`[Kritik Hata] ${reason}. 2 alternatif de başarısız oldu! Sistem en başa döndürülüyor...`);
149
 
150
  baglantiTuru = "Yok";
151
  botIsReady = false;
 
152
 
153
  stopPeriodicHomeChecks();
154
- safeDestroyAllConnections(); // Tüm asılı soketleri işletim sistemi seviyesinde imha et
155
 
156
  if (config.utils && config.utils["auto-reconnect"]) {
157
  triggerSafeReconnect();
158
  }
159
  };
160
 
161
- // Yedek Plan: Doğrudan Minecraft Sunucusuna Bağlanma
162
  const connectDirectly = (reason) => {
163
  if (fallbackTriggered) return;
164
  fallbackTriggered = true;
165
 
166
- logger.warn(`[Bağlantı Yedekleme] SSH Tüneli başarısız oldu (${reason}). Normal IP üzerinden GERÇEK TCP bağlantısı kuruluyor...`);
167
 
168
- try { sshClient.end(); } catch (e) {}
 
 
169
 
170
  const socket = net.connect({
171
  host: targetServerIp,
172
  port: parseInt(targetServerPort) || 25565
173
  });
174
- currentSocket = socket; // Global referansa eşitle
 
 
 
175
 
 
176
  const directTimeout = setTimeout(() => {
 
 
 
177
  socket.destroy();
178
- handleFinalFailure("Normal IP bağlantısı zaman aşımına uğradı (Sunucu yanıt vermiyor)");
179
- }, 10000);
180
 
181
  socket.on('connect', () => {
 
 
 
182
  clearTimeout(directTimeout);
183
- logger.info("[Bağlantı Yedekleme] Normal IP üzerinden GERÇEK TCP bağlantısı başarıyla kuruldu!");
184
  baglantiTuru = "Normal";
185
- client.setSocket(socket);
186
- client.emit('connect');
 
 
187
  });
188
 
189
  socket.on('error', (err) => {
 
 
 
190
  clearTimeout(directTimeout);
191
- logger.error(`[Bağlantı Yedekleme Hatası] Normal IP ile de sunucuya bağlanılamadı: ${err.message}`);
192
- handleFinalFailure(`Normal IP hatası: ${err.message}`);
193
  });
194
 
195
  socket.on('close', () => {
 
 
 
196
  clearTimeout(directTimeout);
197
  handleFinalFailure("Normal TCP soketi kapandı");
198
  });
199
  };
200
 
201
- // Dinamik SSH Sunucusuna Bağlanılıyor
202
- logger.info(`[SSH Tünel] SSH üzerinden ${sshConfig.host} sunucusuna (${sshConfig.username}) bağlanılıyor...`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
 
204
  const connectionTimeout = setTimeout(() => {
205
  connectDirectly("SSH Bağlantı Zaman Aşımı (10 saniye yanıt alınamadı)");
@@ -222,25 +236,33 @@ async function createBot() {
222
 
223
  logger.info("[SSH Tünel] Tünel başarıyla kuruldu! Mineflayer sokete bağlanıyor.");
224
  baglantiTuru = "SSH";
225
- currentStream = stream; // Global referansa eşitle
226
 
227
- stream.on('close', () => {
228
- connectDirectly("Tünel stream kapandı");
 
 
229
  });
230
 
231
- stream.on('error', (e) => {
232
- connectDirectly(`Stream hatası: ${e.message}`);
 
 
233
  });
234
 
235
- client.setSocket(stream);
236
- client.emit('connect');
 
 
237
  }
238
  );
239
  });
240
 
241
  sshClient.on('error', (err) => {
242
  clearTimeout(connectionTimeout);
243
- connectDirectly(`SSH Sunucu Hatası: ${err.message}`);
 
 
244
  });
245
 
246
  try {
@@ -254,7 +276,6 @@ async function createBot() {
254
 
255
  bot.loadPlugin(pathfinder);
256
 
257
- // --- TİMİNG SIFIRLAMA İÇİN YARDIMCI PARAMETRELER ---
258
  let lastFullFeedAt = 0;
259
  let windowOpenResolvers = [];
260
  let periodicHandle = null;
@@ -273,7 +294,13 @@ async function createBot() {
273
  activeTimeouts = [];
274
  }
275
 
276
- // --- YARDIMCI FONKSİYONLAR ---
 
 
 
 
 
 
277
  function stripColorCodes(s) {
278
  if (!s || typeof s !== "string") return s;
279
  return s.replace(/§[0-9a-fk-or]/gi, "");
@@ -393,16 +420,19 @@ async function createBot() {
393
  }
394
 
395
  async function goHome() {
 
396
  logger.info(`[${currentBotUsername}] ${GO_HOME_COMMAND} komutu gönderiliyor.`);
397
  bot.chat(GO_HOME_COMMAND);
398
  }
399
 
400
  async function returnIsland() {
 
401
  logger.info(`[${currentBotUsername}] ${RETURN_ISLAND_COMMAND} komutu gönderiliyor.`);
402
  bot.chat(RETURN_ISLAND_COMMAND);
403
  }
404
 
405
  async function scanAndFeed() {
 
406
  if (Date.now() < (lastFullFeedAt + FULL_FEED_COOLDOWN_MS)) return;
407
  const arr = Object.values(bot.entities);
408
  let best = null;
@@ -453,31 +483,35 @@ async function createBot() {
453
  } catch (err) {}
454
  }
455
 
456
- // --- BOT SPAWN / EVENT DİNLEYİCİLERİ ---
457
  bot.once("spawn", async () => {
458
- // BOT BAŞARIYLA SUNUCUYA GİRDİ: Kilidi kaldır ve durumu güncelle
459
  isConnecting = false;
 
460
  bot.pathfinder.setMovements(new Movements(bot));
461
  logger.info("Bot sunucuya giriş yaptı.");
462
  botIsReady = true;
 
463
 
464
- // EXPRESS CHAT ENTEGRASYONU: Her yeni bot doğduğunda tek bir temiz event dinleyici eklenir.
465
  bot.on('message', globalMinecraftMessageListener);
466
 
467
  if (config.utils && config.utils["auto-auth"] && config.utils["auto-auth"].enabled) {
468
  const password = config.utils["auto-auth"].password;
469
 
470
  setSafeTimeout(() => {
471
- bot.chat(`/login ${password}`);
472
- logger.info(`[${currentBotUsername}] Login komutu kullanıldı.`);
 
 
473
  }, 2500);
474
 
475
  setSafeTimeout(() => {
476
- bot.chat(`/skyblock`);
477
- logger.info(`[${currentBotUsername}] Skyblock'a ışınlanma komutu kullanıldı.`);
 
 
478
  }, 7500);
479
 
480
  setSafeTimeout(async () => {
 
481
  await goHome();
482
  await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
483
  await scanAndFeed();
@@ -485,6 +519,7 @@ async function createBot() {
485
  await returnIsland();
486
 
487
  periodicHandle = setInterval(async () => {
 
488
  if (Date.now() < (lastFullFeedAt + FULL_FEED_COOLDOWN_MS)) return;
489
  await goHome();
490
  await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
@@ -497,37 +532,48 @@ async function createBot() {
497
  });
498
 
499
  bot.on("windowOpen", (window) => {
 
500
  const title = parseWindowTitleToString(window.title).toLowerCase();
501
  if (!title.includes("besleyici") && !parseWindowTitleToString(window.title).includes("ʙᴇsʟᴇʏiᴄi")) {
502
  logger.info(`[${currentBotUsername}] Bi chest açıldı ama window title ı uyuşmadığı için kapatıldı. ${parseWindowTitleToString(window.title)}`);
503
- bot.closeWindow(window);
504
  return;
505
  }
506
  const beefSlot = window.slots.find(s => s?.name === "cooked_beef");
507
  const can = extractMinyonCanFromSlot(beefSlot);
 
508
  if (can != null) {
 
 
 
509
  if (can <= 2) {
510
- bot.clickWindow(36, 0, 0);
511
  lastFullFeedAt = Date.now();
 
512
  logger.info(`[${currentBotUsername}] Minyon canı ${can} olduğu için beslendi. 50dk bekleme aktif.`);
513
  } else if (can >= 10) {
514
  lastFullFeedAt = Date.now();
 
515
  logger.info(`[${currentBotUsername}] Minyon canı ${can} (tam). 50dk bekleme aktif.`);
516
  } else {
517
  logger.info(`[${currentBotUsername}] Minyon canı ${can} olduğu için yenilenmedi.`);
518
  }
519
  }
520
- setSafeTimeout(() => { try { bot.closeWindow(window); } catch(e){} }, 500);
521
- while (windowOpenResolvers.length > 0) windowOpenResolvers.shift()();
 
 
 
522
  });
523
 
524
  bot.on("end", () => {
525
- logger.warn("Bağlantı koptu. Tüm zamanlayıcılar sıfırlanıyor...");
526
  stopPeriodicHomeChecks();
527
  botIsReady = false;
528
  baglantiTuru = "Yok";
 
529
 
530
- safeDestroyAllConnections(); // Tüm asılı soketleri ve eski bot referanslarını tamamen imha et
531
 
532
  if (config.utils && config.utils["auto-reconnect"]) {
533
  triggerSafeReconnect();
@@ -535,43 +581,46 @@ async function createBot() {
535
  });
536
 
537
  bot.on("kicked", (reason) => logger.warn(`Bot sunucudan atıldı: ${util.inspect(reason)}`));
538
- bot.on("error", (err) => logger.error(`${err}`));
539
  }
540
 
541
- // --- GARANTİ SOKET VE BAĞLANTI İMHA FONKSİYONU ---
542
  function safeDestroyAllConnections() {
543
- isConnecting = false; // Kilidi serbest bırak ki yeni döngü başlayabilsin
 
 
544
 
545
- // 3D Görüntüleyiciyi kapat ve RAM'den düşür
546
  if (viewerInstance && typeof viewerInstance.close === 'function') {
547
- try { viewerInstance.close(); } catch(e){}
 
 
 
 
 
548
  }
549
  viewerInstance = null;
550
  if (bot) { bot.viewer = null; }
551
 
552
- // Tüm soket bacaklarını ve tünelleri işletim sistemi seviyesinde imha et (Kibarlık yok, direkt destroy)
553
  if (currentStream && typeof currentStream.destroy === 'function') {
554
  try { currentStream.destroy(); } catch(e){}
555
  }
556
  if (currentSocket && typeof currentSocket.destroy === 'function') {
557
  try { currentSocket.destroy(); } catch(e){}
558
  }
559
- if (currentSshClient && typeof currentSshClient.end === 'function') {
560
- try { currentSshClient.end(); } catch(e){}
561
  }
562
 
563
  currentStream = null;
564
  currentSocket = null;
565
  currentSshClient = null;
566
 
567
- // Eski bot nesnesinin event listener'larını temizle ve Garbage Collector'a teslim et
568
  if (bot) {
569
- try { bot.removeAllListeners(); } catch(e){}
 
570
  bot = null;
571
  }
572
  }
573
 
574
- // --- RECONNECT ÇAKIŞMALARINI ENGELLEYEN GÜVENLİ ZAMANLAYICI ---
575
  function triggerSafeReconnect() {
576
  if (reconnectTimeout) {
577
  clearTimeout(reconnectTimeout);
@@ -580,11 +629,10 @@ function triggerSafeReconnect() {
580
  logger.info(`[Sistem] ${delay} ms sonra tekil bir hat üzerinden sistem sıfırdan başlatılacak...`);
581
 
582
  reconnectTimeout = setTimeout(() => {
583
- createBot();
584
  }, delay);
585
  }
586
 
587
- // --- EXPRESS VE BOTU BİRBİRİNDEN AYIRAN GLOBAL SOHBET DİNLEYİCİSİ (RAM SIZINTISI GARANTİ ÇÖZÜMÜ) ---
588
  function globalMinecraftMessageListener(jsonMsg) {
589
  try {
590
  if (!bot) return;
@@ -611,16 +659,30 @@ const app = express();
611
  const http = require('http');
612
 
613
  app.get("/status", (req, res) => {
 
 
 
 
 
 
 
 
 
 
 
 
614
  res.send({
615
  ready: botIsReady,
616
  username: bot ? bot.username : null,
617
- connection_type: baglantiTuru
 
 
 
618
  });
619
  });
620
 
621
  app.get("/", (req, res) => res.send("Bot Aktif"));
622
 
623
- // EXPRESS /messages YENİDEN YAPILANDIRILDI: Express artık bota doğrudan 'on' kancası atmaz. RAM sızıntısı bitti.
624
  app.get("/messages", (req, res) => {
625
  if (messagesTimeout) {
626
  clearTimeout(messagesTimeout);
@@ -636,7 +698,6 @@ app.get("/messages", (req, res) => {
636
  logs: activeMessages
637
  });
638
 
639
- // Sohbet paneli 1 dakika izlenmezse RAM koruması için eski mesaj havuzunu temizle
640
  messagesTimeout = setTimeout(() => {
641
  activeMessages = [];
642
  messagesTimeout = null;
@@ -702,7 +763,7 @@ app.get("/restart", (req, res) => {
702
  try { bot.chat("Bot web paneli uzerinden tum kodlariyla yeniden baslatiliyor..."); } catch(e){}
703
  res.send({ success: true, message: "Tüm proje kapatıldı. Hugging Face sistemi birkaç saniye içinde kodu sıfırdan başlatacak." });
704
  setTimeout(() => {
705
- if (bot) bot.quit();
706
  logger.info("[Sistem] process.exit(0) çağrıldı. Konteyner yeniden başlatılacak.");
707
  process.exit(0);
708
  }, 1000);
@@ -755,6 +816,9 @@ server.on('upgrade', (req, socket, head) => {
755
  viewerTimeout = setTimeout(() => {
756
  if (viewerInstance && typeof viewerInstance.close === 'function') {
757
  try {
 
 
 
758
  viewerInstance.close();
759
  if (bot) bot.viewer = null;
760
  viewerInstance = null;
 
27
  let bot = null;
28
  let botIsReady = false;
29
  let baglantiTuru = "Yok";
30
+ let activeMessages = [];
31
+ let messagesTimeout = null;
32
  const ansiToHtmlConvert = new (require('ansi-to-html'))({ newline: true });
33
 
34
+ // --- GÜVENLİ BAĞLANTI DEĞİŞKENLERİ ---
35
+ let isConnecting = false;
36
+ let isDestroying = false;
37
+ let reconnectTimeout = null;
38
+ let currentSshClient = null;
39
+ let currentStream = null;
40
+ let currentSocket = null;
41
+
42
+ // --- PANEL METRİKLERİ ---
43
+ let botUptimeStart = null;
44
+ let lastFullFeedTimeStr = "Henüz besleme yapılmadı";
45
+ let lastCheckTimeStr = "Henüz kontrol yapılmadı";
46
 
47
  // Dış IP tespiti
48
  https.get('https://api.ipify.org?format=json', (res) => {
 
52
  try {
53
  const ipInfo = JSON.parse(data);
54
  console.log(`Dış IP adresin: ${ipInfo.ip}`);
55
+ } catch (err) {}
 
 
56
  });
57
+ }).on('error', () => {});
 
 
58
 
59
  async function createBot() {
 
60
  if (isConnecting) {
61
  logger.warn("[Sistem] Zaten aktif bir bağlantı süreci yürütülüyor. Mükerrer istek engellendi.");
62
  return;
63
  }
64
+ isConnecting = true;
65
+ isDestroying = false;
66
 
67
  const net = require('net');
68
  const sshClient = new Client();
69
+ currentSshClient = sshClient;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  const targetServerIp = config.server.ip;
72
  const targetServerPort = config.server.port;
73
+ const currentBotUsername = config["bot-account"]["username"];
74
 
 
75
  bot = mineflayer.createBot({
76
  username: currentBotUsername,
77
  auth: config["bot-account"]["type"],
 
79
  port: targetServerPort,
80
  version: config.server.version,
81
 
82
+ connect: async (client) => {
83
  let fallbackTriggered = false;
84
  let isFinalFailureHandled = false;
85
 
 
86
  const handleFinalFailure = (reason) => {
87
  if (isFinalFailureHandled) return;
88
  isFinalFailureHandled = true;
89
 
90
+ logger.error(`[Kritik Hata] ${reason}. Bağlantı sağlanamadı! Sistem en başa döndürülüyor...`);
91
 
92
  baglantiTuru = "Yok";
93
  botIsReady = false;
94
+ botUptimeStart = null;
95
 
96
  stopPeriodicHomeChecks();
97
+ safeDestroyAllConnections();
98
 
99
  if (config.utils && config.utils["auto-reconnect"]) {
100
  triggerSafeReconnect();
101
  }
102
  };
103
 
 
104
  const connectDirectly = (reason) => {
105
  if (fallbackTriggered) return;
106
  fallbackTriggered = true;
107
 
108
+ logger.warn(`[Bağlantı Yedekleme] Doğrudan IP moduna geçiliyor (Sebep: ${reason}). Kendi (Yurt dışı) IP'miz üzerinden GERÇEK TCP bağlantısı kuruluyor...`);
109
 
110
+ if (sshClient) {
111
+ try { sshClient.destroy(); } catch (e) {}
112
+ }
113
 
114
  const socket = net.connect({
115
  host: targetServerIp,
116
  port: parseInt(targetServerPort) || 25565
117
  });
118
+ currentSocket = socket;
119
+
120
+ // KESİN ÇÖZÜM KİLİDİ: 1 dakikalık süreçte hem sunucu hatasının hem de timeout'un aynı anda çift tetiklenmesini engeller
121
+ let isDirectHandled = false;
122
 
123
+ // İstediğin gibi: Kendi IP'si için zaman aşımı toleransını tam 1 dakikaya (60.000 ms) çıkardık
124
  const directTimeout = setTimeout(() => {
125
+ if (isDirectHandled) return;
126
+ isDirectHandled = true;
127
+
128
  socket.destroy();
129
+ handleFinalFailure("Kendi IP bağlantısı 1 dakikalık süre içinde zaman aşımına uğradı (Sunucu yanıt vermedi)");
130
+ }, 60000);
131
 
132
  socket.on('connect', () => {
133
+ if (isDirectHandled) return;
134
+ isDirectHandled = true;
135
+
136
  clearTimeout(directTimeout);
137
+ logger.info("[Bağlantı Yedekleme] Kendi IP'miz üzerinden GERÇEK TCP bağlantısı başarıyla kuruldu!");
138
  baglantiTuru = "Normal";
139
+ if (client && typeof client.setSocket === 'function') {
140
+ client.setSocket(socket);
141
+ client.emit('connect');
142
+ }
143
  });
144
 
145
  socket.on('error', (err) => {
146
+ if (isDirectHandled) return;
147
+ isDirectHandled = true;
148
+
149
  clearTimeout(directTimeout);
150
+ logger.error(`[Bağlantı Yedekleme Hatası] Sunucu bağlantıyı reddetti veya olumsuz yanıt verdi: ${err.message}`);
151
+ handleFinalFailure(`Kendi IP hatası: ${err.message}`);
152
  });
153
 
154
  socket.on('close', () => {
155
+ if (isDirectHandled) return;
156
+ isDirectHandled = true;
157
+
158
  clearTimeout(directTimeout);
159
  handleFinalFailure("Normal TCP soketi kapandı");
160
  });
161
  };
162
 
163
+ const githubRawUrl = 'https://raw.githubusercontent.com/suvarileader/che/refs/heads/main/doc/ower/doc.json';
164
+ logger.info("[GitHub Config] Güncel SSH tünel bilgileri GitHub'dan çekiliyor...");
165
+
166
+ let remoteData = null;
167
+ try {
168
+ remoteData = await new Promise((resolve, reject) => {
169
+ const reqTimeout = setTimeout(() => {
170
+ reject(new Error("GitHub bağlantısı 6 saniye içinde yanıt vermedi (Timeout)"));
171
+ }, 6000);
172
+
173
+ https.get(githubRawUrl, (res) => {
174
+ clearTimeout(reqTimeout);
175
+ let body = '';
176
+ res.on('data', chunk => body += chunk);
177
+ res.on('end', () => {
178
+ try {
179
+ resolve(JSON.parse(body));
180
+ } catch (e) {
181
+ reject(new Error("JSON Ayrıştırma Hatası"));
182
+ }
183
+ });
184
+ }).on('error', (err) => {
185
+ clearTimeout(reqTimeout);
186
+ reject(err);
187
+ });
188
+ });
189
+ } catch (err) {
190
+ connectDirectly(`GitHub verisi alınamadı veya sayfa çöktü (${err.message})`);
191
+ return;
192
+ }
193
+
194
+ let sshConfig = null;
195
+ if (remoteData && Array.isArray(remoteData)) {
196
+ const myConfig = remoteData.find(item => item && item.account === currentBotUsername);
197
+ if (myConfig) {
198
+ sshConfig = {
199
+ host: (myConfig.serverName && myConfig.serverName !== "empty") ? myConfig.serverName : null,
200
+ port: 22,
201
+ username: (myConfig.username && myConfig.username !== "empty") ? myConfig.username : null,
202
+ password: (myConfig.pass && myConfig.pass !== "empty") ? myConfig.pass : config.utils["auto-auth"].password
203
+ };
204
+
205
+ if (!sshConfig.host || !sshConfig.username) {
206
+ sshConfig = null;
207
+ }
208
+ }
209
+ }
210
+
211
+ if (!sshConfig) {
212
+ connectDirectly(`GitHub listesinde '${currentBotUsername}' botu ile uyumlu geçerli SSH verisi bulunamadı`);
213
+ return;
214
+ }
215
+
216
+ logger.info(`[SSH Tünel] GitHub'dan alınan ${sshConfig.host} sunucusuna (${sshConfig.username}) bağlanılıyor...`);
217
 
218
  const connectionTimeout = setTimeout(() => {
219
  connectDirectly("SSH Bağlantı Zaman Aşımı (10 saniye yanıt alınamadı)");
 
236
 
237
  logger.info("[SSH Tünel] Tünel başarıyla kuruldu! Mineflayer sokete bağlanıyor.");
238
  baglantiTuru = "SSH";
239
+ currentStream = stream;
240
 
241
+ stream.once('close', () => {
242
+ if (!fallbackTriggered && !isDestroying) {
243
+ connectDirectly("Tünel stream kapandı");
244
+ }
245
  });
246
 
247
+ stream.once('error', (e) => {
248
+ if (!fallbackTriggered && !isDestroying) {
249
+ connectDirectly(`Stream hatası: ${e.message}`);
250
+ }
251
  });
252
 
253
+ if (client && typeof client.setSocket === 'function') {
254
+ client.setSocket(stream);
255
+ client.emit('connect');
256
+ }
257
  }
258
  );
259
  });
260
 
261
  sshClient.on('error', (err) => {
262
  clearTimeout(connectionTimeout);
263
+ if (!fallbackTriggered && !isDestroying) {
264
+ connectDirectly(`SSH Sunucu Hatası: ${err.message}`);
265
+ }
266
  });
267
 
268
  try {
 
276
 
277
  bot.loadPlugin(pathfinder);
278
 
 
279
  let lastFullFeedAt = 0;
280
  let windowOpenResolvers = [];
281
  let periodicHandle = null;
 
294
  activeTimeouts = [];
295
  }
296
 
297
+ function getExtendedDateTimeString() {
298
+ const now = new Date();
299
+ const dateStr = now.toLocaleDateString('tr-TR', { day: '2-digit', month: '2-digit', year: 'numeric' });
300
+ const timeStr = now.toLocaleTimeString('tr-TR');
301
+ return `${dateStr} - ${timeStr}`;
302
+ }
303
+
304
  function stripColorCodes(s) {
305
  if (!s || typeof s !== "string") return s;
306
  return s.replace(/§[0-9a-fk-or]/gi, "");
 
420
  }
421
 
422
  async function goHome() {
423
+ if (!bot || !botIsReady) return;
424
  logger.info(`[${currentBotUsername}] ${GO_HOME_COMMAND} komutu gönderiliyor.`);
425
  bot.chat(GO_HOME_COMMAND);
426
  }
427
 
428
  async function returnIsland() {
429
+ if (!bot || !botIsReady) return;
430
  logger.info(`[${currentBotUsername}] ${RETURN_ISLAND_COMMAND} komutu gönderiliyor.`);
431
  bot.chat(RETURN_ISLAND_COMMAND);
432
  }
433
 
434
  async function scanAndFeed() {
435
+ if (!bot || !botIsReady) return;
436
  if (Date.now() < (lastFullFeedAt + FULL_FEED_COOLDOWN_MS)) return;
437
  const arr = Object.values(bot.entities);
438
  let best = null;
 
483
  } catch (err) {}
484
  }
485
 
 
486
  bot.once("spawn", async () => {
 
487
  isConnecting = false;
488
+ if (!bot) return;
489
  bot.pathfinder.setMovements(new Movements(bot));
490
  logger.info("Bot sunucuya giriş yaptı.");
491
  botIsReady = true;
492
+ botUptimeStart = Date.now();
493
 
 
494
  bot.on('message', globalMinecraftMessageListener);
495
 
496
  if (config.utils && config.utils["auto-auth"] && config.utils["auto-auth"].enabled) {
497
  const password = config.utils["auto-auth"].password;
498
 
499
  setSafeTimeout(() => {
500
+ if (bot && botIsReady) {
501
+ bot.chat(`/login ${password}`);
502
+ logger.info(`[${currentBotUsername}] Login komutu kullanıldı.`);
503
+ }
504
  }, 2500);
505
 
506
  setSafeTimeout(() => {
507
+ if (bot && botIsReady) {
508
+ bot.chat(`/skyblock`);
509
+ logger.info(`[${currentBotUsername}] Skyblock'a ışınlanma komutu kullanıldı.`);
510
+ }
511
  }, 7500);
512
 
513
  setSafeTimeout(async () => {
514
+ if (!bot || !botIsReady) return;
515
  await goHome();
516
  await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
517
  await scanAndFeed();
 
519
  await returnIsland();
520
 
521
  periodicHandle = setInterval(async () => {
522
+ if (!bot || !botIsReady) return;
523
  if (Date.now() < (lastFullFeedAt + FULL_FEED_COOLDOWN_MS)) return;
524
  await goHome();
525
  await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
 
532
  });
533
 
534
  bot.on("windowOpen", (window) => {
535
+ if (!bot) return;
536
  const title = parseWindowTitleToString(window.title).toLowerCase();
537
  if (!title.includes("besleyici") && !parseWindowTitleToString(window.title).includes("ʙᴇsʟᴇʏiᴄi")) {
538
  logger.info(`[${currentBotUsername}] Bi chest açıldı ama window title ı uyuşmadığı için kapatıldı. ${parseWindowTitleToString(window.title)}`);
539
+ try { bot.closeWindow(window); } catch(e){}
540
  return;
541
  }
542
  const beefSlot = window.slots.find(s => s?.name === "cooked_beef");
543
  const can = extractMinyonCanFromSlot(beefSlot);
544
+
545
  if (can != null) {
546
+ const currentStamp = getExtendedDateTimeString();
547
+ lastCheckTimeStr = `${currentStamp} (Okunan Can: ${can})`;
548
+
549
  if (can <= 2) {
550
+ try { bot.clickWindow(36, 0, 0); } catch(e){}
551
  lastFullFeedAt = Date.now();
552
+ lastFullFeedTimeStr = `${currentStamp} (Minyon canı ${can} iken başarıyla beslendi)`;
553
  logger.info(`[${currentBotUsername}] Minyon canı ${can} olduğu için beslendi. 50dk bekleme aktif.`);
554
  } else if (can >= 10) {
555
  lastFullFeedAt = Date.now();
556
+ lastFullFeedTimeStr = `${currentStamp} (Canı ${can} olduğu için besleme gerekmedi)`;
557
  logger.info(`[${currentBotUsername}] Minyon canı ${can} (tam). 50dk bekleme aktif.`);
558
  } else {
559
  logger.info(`[${currentBotUsername}] Minyon canı ${can} olduğu için yenilenmedi.`);
560
  }
561
  }
562
+ setSafeTimeout(() => { if (bot) { try { bot.closeWindow(window); } catch(e){} } }, 500);
563
+ while (windowOpenResolvers.length > 0) {
564
+ const fn = windowOpenResolvers.shift();
565
+ if (typeof fn === 'function') fn();
566
+ }
567
  });
568
 
569
  bot.on("end", () => {
570
+ logger.warn("Bağlantı koptu. Tüm zamanlayıcılar sıfırlanıyor ve YENİDEN BAĞLANMA SÜRECİ BAŞLIYOR...");
571
  stopPeriodicHomeChecks();
572
  botIsReady = false;
573
  baglantiTuru = "Yok";
574
+ botUptimeStart = null;
575
 
576
+ safeDestroyAllConnections();
577
 
578
  if (config.utils && config.utils["auto-reconnect"]) {
579
  triggerSafeReconnect();
 
581
  });
582
 
583
  bot.on("kicked", (reason) => logger.warn(`Bot sunucudan atıldı: ${util.inspect(reason)}`));
584
+ bot.on("error", (err) => logger.error(`Mineflayer Hatası: ${err}`));
585
  }
586
 
 
587
  function safeDestroyAllConnections() {
588
+ if (isDestroying) return;
589
+ isDestroying = true;
590
+ isConnecting = false;
591
 
 
592
  if (viewerInstance && typeof viewerInstance.close === 'function') {
593
+ try {
594
+ if (viewerInstance.ws && typeof viewerInstance.ws.close === 'function') {
595
+ viewerInstance.ws.close();
596
+ }
597
+ viewerInstance.close();
598
+ } catch(e){}
599
  }
600
  viewerInstance = null;
601
  if (bot) { bot.viewer = null; }
602
 
 
603
  if (currentStream && typeof currentStream.destroy === 'function') {
604
  try { currentStream.destroy(); } catch(e){}
605
  }
606
  if (currentSocket && typeof currentSocket.destroy === 'function') {
607
  try { currentSocket.destroy(); } catch(e){}
608
  }
609
+ if (currentSshClient && typeof currentSshClient.destroy === 'function') {
610
+ try { currentSshClient.destroy(); } catch(e){}
611
  }
612
 
613
  currentStream = null;
614
  currentSocket = null;
615
  currentSshClient = null;
616
 
 
617
  if (bot) {
618
+ try { bot.removeListener('message', globalMinecraftMessageListener); } catch(e){}
619
+ try { bot.quit(); } catch(e){}
620
  bot = null;
621
  }
622
  }
623
 
 
624
  function triggerSafeReconnect() {
625
  if (reconnectTimeout) {
626
  clearTimeout(reconnectTimeout);
 
629
  logger.info(`[Sistem] ${delay} ms sonra tekil bir hat üzerinden sistem sıfırdan başlatılacak...`);
630
 
631
  reconnectTimeout = setTimeout(() => {
632
+ createBot(); // SONSUZ DÖNGÜ GARANTİSİ: Ne olursa olsun bu fonksiyon taze kilitlerle tekrar tetiklenir
633
  }, delay);
634
  }
635
 
 
636
  function globalMinecraftMessageListener(jsonMsg) {
637
  try {
638
  if (!bot) return;
 
659
  const http = require('http');
660
 
661
  app.get("/status", (req, res) => {
662
+ let uptimeString = "Bağlı Değil";
663
+ if (botIsReady && botUptimeStart) {
664
+ const diffMs = Date.now() - botUptimeStart;
665
+ const diffSecs = Math.floor(diffMs / 1000);
666
+ const days = Math.floor(diffSecs / 86400);
667
+ const hours = Math.floor((diffSecs % 86400) / 3600);
668
+ const mins = Math.floor((diffSecs % 3600) / 60);
669
+ const secs = diffSecs % 60;
670
+
671
+ uptimeString = `${days} Gün, ${hours} Saat, ${mins} Dakika, ${secs} Saniye`;
672
+ }
673
+
674
  res.send({
675
  ready: botIsReady,
676
  username: bot ? bot.username : null,
677
+ connection_type: baglantiTuru,
678
+ bot_uptime: uptimeString,
679
+ last_minyon_check: lastCheckTimeStr,
680
+ last_minyon_feed: lastFullFeedTimeStr
681
  });
682
  });
683
 
684
  app.get("/", (req, res) => res.send("Bot Aktif"));
685
 
 
686
  app.get("/messages", (req, res) => {
687
  if (messagesTimeout) {
688
  clearTimeout(messagesTimeout);
 
698
  logs: activeMessages
699
  });
700
 
 
701
  messagesTimeout = setTimeout(() => {
702
  activeMessages = [];
703
  messagesTimeout = null;
 
763
  try { bot.chat("Bot web paneli uzerinden tum kodlariyla yeniden baslatiliyor..."); } catch(e){}
764
  res.send({ success: true, message: "Tüm proje kapatıldı. Hugging Face sistemi birkaç saniye içinde kodu sıfırdan başlatacak." });
765
  setTimeout(() => {
766
+ if (bot) { try { bot.quit(); } catch(e){} }
767
  logger.info("[Sistem] process.exit(0) çağrıldı. Konteyner yeniden başlatılacak.");
768
  process.exit(0);
769
  }, 1000);
 
816
  viewerTimeout = setTimeout(() => {
817
  if (viewerInstance && typeof viewerInstance.close === 'function') {
818
  try {
819
+ if (viewerInstance.ws && typeof viewerInstance.ws.close === 'function') {
820
+ viewerInstance.ws.close();
821
+ }
822
  viewerInstance.close();
823
  if (bot) bot.viewer = null;
824
  viewerInstance = null;