IRCdForum.Net  

Ana Sayfa

Geri Git   IRCdForum.Net > IRCd Genel > UnrealIRCd

UnrealIRCd UnrealIRCd tabanlý sunucunuzda rastladýðýnýz sorunlarýn çözümüne bu bölümden ulaþabilirsiniz.


Python BNC bot

UnrealIRCd tabanlý sunucunuzda rastladýðýnýz sorunlarýn çözümüne bu bölümden ulaþabilirsiniz.


Kullanýcý Etiket Listesi

2Beðeniler
  • 2 Post By TeMoNDe

 
 
LinkBack Konu Araçlarý Görünüm Modlarý
Eski 02 Nisan 2026, 09:39   #1
Çevrimdýþý
TeMoNDe
Çevrimdýþý

irc.Sohbetix.net

TeMoNDe Kullanýcýsýnýn Avatarý

Varsayýlan Python BNC bot

Merhaba arkadaslar,
Ilgili kategorinin olmamasindan dolayi konuyu buraya aciyorum. Belki daha sonra tasinabilir.
Bu botu normal bnc'den cok nickim o sunucuda online gozuksun diye kodlamistim. Botun islevi ayarladiginiz ana sunucu ve kanala baglanir, !ekle komutu ile eklediginiz sunucuya ayarladiginiz nicki sokar (eger ayarlarsaniz kayit eder nicki). DC yeme durumunda vs tekrar baglanir. !durum komutu ile botu takip edebilir ozeline gelen son 5 mesaji gorebilirsiniz. Dilerseniz kodlari inceleyip kendinize gore daha da gelistirebilirsiniz.

Kod:
import socket
import time
import threading
import logging
import json
import os
import re
import collections

# ─── ANA BOT AYARLARI (BncBot - irc.zevklisohbet.net) ────────────────────────
MASTER_SERVER   = "irc.sohbetix.net"
MASTER_PORT     = 6667
MASTER_NICK     = "BncBot"
MASTER_PASSWORD = ""
MASTER_CHANNEL  = "#bnc"
MASTER_IDENT    = "bncbot"
MASTER_REALNAME = "BncBot Controller"

# ─── OPER BÝLGÝLERÝ â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
OPER_NAME     = "Eggdrop"
OPER_PASSWORD = ""

# ─── SLAVE BOT AYARLARI ───────────────────────────────────────────────────────
SLAVE_NICK     = "ArsivDK"
SLAVE_PASSWORD = ""
SLAVE_CHANNEL  = "#Sohbet"
SLAVE_IDENT    = "Arsivci"
SLAVE_REALNAME = "www.Arsiv.dk"
SLAVE_PORT     = 6667
SLAVE_EMAIL    = ""

# ─── GENEL AYARLAR ────────────────────────────────────────────────────────────
RECONNECT_DELAY  = 10
PING_TIMEOUT     = 300
BOT_OWNER        = ""
DB_FILE          = "servers.json"
LOG_DIR          = "logs"          # Her sunucu için ayrý log klasörü
DAILY_REPORT_HOUR = 9              # Günlük özet saati (sunucu saati)
SLAVE_PING_INTERVAL = 60           # Slave'e PING gönderme aralýðý (sn)
SLAVE_PING_TIMEOUT  = 120          # Bu kadar sn içinde PONG gelmezse reconnect
# ──────────────────────────────────────────────────────────────────────────────

os.makedirs(LOG_DIR, exist_ok=True)

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)
log = logging.getLogger("IRCBot")

slave_bots: dict  = {}
slave_lock        = threading.Lock()
watch_keywords: list = []          # [(keyword, ekleyen_nick), ...]
watch_lock        = threading.Lock()
master_ref        = None           # MasterBot instance (bildirim için)


# ══════════════════════════════════════════════════════════════════════════════
#  YARDIMCI FONKSÝYONLAR
# ══════════════════════════════════════════════════════════════════════════════
def is_nickserv(prefix: str) -> bool:
    return prefix.lstrip(":").split("!")[0].lower() == "nickserv"

def notify_master(msg: str):
    """#bnc kanalýna bildirim gönder."""
    global master_ref
    if master_ref:
        try:
            master_ref.send(f"PRIVMSG {MASTER_CHANNEL} :{msg}")
        except Exception:
            pass

def get_server_logger(server: str) -> logging.Logger:
    """Her sunucu için ayrý dosya logger'ý döndürür."""
    name = server.replace(".", "_").replace(":", "_")
    logger = logging.getLogger(f"srv.{name}")
    if not logger.handlers:
        fh = logging.FileHandler(
            os.path.join(LOG_DIR, f"{name}.log"),
            encoding="utf-8"
        )
        fh.setFormatter(logging.Formatter(
            "%(asctime)s %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
        ))
        logger.addHandler(fh)
        logger.setLevel(logging.INFO)
        logger.propagate = False
    return logger


# ══════════════════════════════════════════════════════════════════════════════
#  KAYIT SÝSTEMÝ — servers.json
# ══════════════════════════════════════════════════════════════════════════════
def db_load() -> list:
    if not os.path.exists(DB_FILE):
        return []
    try:
        with open(DB_FILE, "r", encoding="utf-8") as f:
            data = json.load(f)
        log.info(f"[DB] {len(data)} sunucu yüklendi.")
        return data
    except Exception as e:
        log.error(f"[DB] Okuma hatasý: {e}")
        return []

def db_save():
    with slave_lock:
        entries = [{"host": bot.server, "port": bot.port} for bot in slave_bots.values()]
    try:
        with open(DB_FILE, "w", encoding="utf-8") as f:
            json.dump(entries, f, indent=2)
    except Exception as e:
        log.error(f"[DB] Yazma hatasý: {e}")

def db_remove(host: str, port: int):
    entries = db_load()
    entries = [e for e in entries if not (e["host"] == host and e["port"] == port)]
    try:
        with open(DB_FILE, "w", encoding="utf-8") as f:
            json.dump(entries, f, indent=2)
    except Exception as e:
        log.error(f"[DB] Silme hatasý: {e}")


# ══════════════════════════════════════════════════════════════════════════════
#  TEMEL IRC BAÐLANTISI
# ══════════════════════════════════════════════════════════════════════════════
class IRCConnection:
    def __init__(self, server, port, nick, password, channel, ident, realname, label="Bot"):
        self.server   = server
        self.port     = port
        self.nick     = nick
        self.password = password
        self.channel  = channel
        self.ident    = ident
        self.realname = realname
        self.label    = label
        self.sock     = None
        self.running  = True
        self._joined  = False
        self._buffer  = ""

    def connect(self):
        log.info(f"[{self.label}] Baðlanýlýyor: {self.server}:{self.port}")
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.settimeout(PING_TIMEOUT)
        self.sock.connect((self.server, self.port))
        self._joined = False
        self._buffer = ""
        log.info(f"[{self.label}] TCP baðlantýsý kuruldu.")

    def disconnect(self):
        try:
            self.sock.close()
        except Exception:
            pass
        self.sock = None

    def send(self, msg: str):
        raw = (msg + "\r\n").encode("utf-8", errors="replace")
        log.debug(f"[{self.label}] >> {msg}")
        self.sock.sendall(raw)

    def register(self):
        self.send(f"PASS {self.password}")
        self.send(f"NICK {self.nick}")
        self.send(f"USER {self.ident} 0 * :{self.realname}")

    def read_lines(self):
        chunk = self.sock.recv(4096).decode("utf-8", errors="replace")
        if not chunk:
            raise ConnectionResetError("Sunucu baðlantýyý kapattý.")
        self._buffer += chunk
        lines = []
        while "\r\n" in self._buffer:
            line, self._buffer = self._buffer.split("\r\n", 1)
            if line:
                lines.append(line)
        return lines

    def stop(self):
        self.running = False
        try:
            self.send("QUIT :Bot kaldýrýldý.")
        except Exception:
            pass
        time.sleep(0.5)
        self.disconnect()


# ══════════════════════════════════════════════════════════════════════════════
#  SLAVE BOT
# ══════════════════════════════════════════════════════════════════════════════
class SlaveBot(IRCConnection):
    def __init__(self, server, port=SLAVE_PORT):
        label = f"Slave:{server}"
        super().__init__(server, port, SLAVE_NICK, SLAVE_PASSWORD,
                         SLAVE_CHANNEL, SLAVE_IDENT, SLAVE_REALNAME, label)

        # ── Baðlantý durumu ──────────────────────────────────────────────
        self.status        = "baþlatýlýyor"
        self.connected_at  = None
        self.reconnects    = 0
        self.last_error    = ""
        self.last_activity = time.time()

        # ── Kanal takibi ─────────────────────────────────────────────────
        self.channels: set = set()

        # ── PM takibi (son 20) ────────────────────────────────────────────
        self.pm_log:  list = []
        self.pm_lock       = threading.Lock()

        # ── Nick / NickServ durumu ────────────────────────────────────────
        self.nick_status      = "unknown"
        self._nick_registered = False
        self._register_retry_at  = None
        self._register_retry_sec = 0

        # ── Restart sinyali ──────────────────────────────────────────────
        self._restart_flag = False

        # ── Ýstatistikler ─────────────────────────────────────────────────
        self.msg_count      = 0     # bu oturumda görülen kanal mesajý
        self.pm_count_total = 0     # toplam PM sayýsý
        self.connect_history = collections.deque(maxlen=5)  # son 5 baðlanma/kopma

        # ── PING/PONG takibi ─────────────────────────────────────────────
        self._last_pong     = time.time()
        self._ping_sent_at  = None

        # ── Baðlantý kopma bildirimi ──────────────────────────────────────
        self._notified_disconnect = False

        # ── Günlük rapor ──────────────────────────────────────────────────
        self._last_daily_report = None   # datetime.date

        # ── Sunucu logger ─────────────────────────────────────────────────
        self.srv_log = get_server_logger(server)

    # ── Yardýmcýlar ───────────────────────────────────────────────────────
    def _set_status(self, s: str, err: str = ""):
        self.status     = s
        self.last_error = err

    def _touch(self):
        self.last_activity = time.time()

    def _fmt_duration(self, seconds: int) -> str:
        if seconds < 60:
            return f"{seconds}sn"
        dk, sn = divmod(seconds, 60)
        if dk < 60:
            return f"{dk}dk {sn}sn"
        sa, dk = divmod(dk, 60)
        return f"{sa}sa {dk}dk {sn}sn"

    def _idle_str(self) -> str:
        return self._fmt_duration(int(time.time() - self.last_activity))

    def _uptime_str(self) -> str:
        if not self.connected_at:
            return "-"
        return self._fmt_duration(int(time.time() - self.connected_at))

    # ── Sunucu logu ───────────────────────────────────────────────────────
    def _slog(self, msg: str):
        self.srv_log.info(msg)

    # ── GHOST — nick alýnmýþsa ─────────────────────────────────────────────
    def _try_ghost(self):
        """Asýl nick baþkasý tarafýndan alýnmýþsa GHOST ile geri al."""
        log.info(f"[{self.label}] GHOST deneniyor: {SLAVE_NICK}")
        self.send(f"PRIVMSG NickServ :GHOST {SLAVE_NICK} {self.password}")
        time.sleep(2)
        self.send(f"NICK {SLAVE_NICK}")

    # ── NickServ mesajýný iþle ────────────────────────────────────────────
    def _handle_nickserv(self, body: str):
        # ── Identify baþarýlý ─────────────────────────────────────────────
        if any(k in body for k in (
            "sifre kabul edildi", "zaten identify", "login oldunuz",
            "you are now identified", "password accepted",
            "identified successfully", "now recognized",
            "you are already identified", "you are already logged in",
        )):
            self.nick_status = "identified"
            log.info(f"[{self.label}] NickServ: identify baþarýlý.")
            return

        # ── Nick kayýtlý deðil → register et ─────────────────────────────
        if any(k in body for k in (
            "kayitli degil", "kayitli de", "kayit altina almak",
            "is not registered", "isn't registered",
            "no such nick", "not registered",
        )):
            self.nick_status = "not_registered"
            if not self._nick_registered:
                self._nick_registered = True
                log.info(f"[{self.label}] NickServ: kayýtlý deðil, register deneniyor.")
                self.send(f"PRIVMSG NickServ :REGISTER {self.password} {SLAVE_EMAIL}")
            return

        # ── Register bekleme süresi ───────────────────────────────────────
        m = re.search(r"(\d+)\s*saniye\s*bekledikten", body)
        if m and self.nick_status == "not_registered":
            sn = int(m.group(1)) + 2
            self._register_retry_at  = time.time() + sn
            self._register_retry_sec = sn
            self._nick_registered    = False
            log.info(f"[{self.label}] NickServ: register için {sn}sn bekleniyor.")
            def _delayed_register(bot=self, delay=sn):
                time.sleep(delay)
                if bot.running and bot.nick_status == "not_registered" and not bot._nick_registered:
                    bot._nick_registered = True
                    log.info(f"[{bot.label}] NickServ: bekleme bitti, register yeniden deneniyor.")
                    try:
                        bot.send(f"PRIVMSG NickServ :REGISTER {bot.password} {SLAVE_EMAIL}")
                    except Exception:
                        pass
            threading.Thread(target=_delayed_register, daemon=True).start()
            return

        # ── Yanlýþ þifre ─────────────────────────────────────────────────
        if any(k in body for k in (
            "password incorrect", "invalid password",
            "authentication failed", "password does not match",
            "yanlis sifre", "hatali sifre",
            "yanlýþ þifre", "hatalý þifre",
        )):
            self.nick_status = "wrong_password"
            log.warning(f"[{self.label}] NickServ: yanlýþ þifre!")
            return

        # ── Register onayý ────────────────────────────────────────────────
        if any(k in body for k in (
            "has been registered", "registration successful",
            "your nick has been registered",
            "kayit edildi", "tescil edildi",
        )):
            self.nick_status         = "registered"
            self._register_retry_at  = None
            self._register_retry_sec = 0
            log.info(f"[{self.label}] NickServ: nick register edildi.")
            return

        # ── Genel identify isteði ─────────────────────────────────────────
        if any(k in body for k in (
            "identify sifreniz", "msg nickserv identify", "/msg nickserv",
        )):
            if self.nick_status not in ("identified", "registered"):
                self.send(f"PRIVMSG NickServ :IDENTIFY {self.password}")

    # ── Keyword izleme ────────────────────────────────────────────────────
    def _check_watch(self, channel: str, sender: str, message: str):
        with watch_lock:
            kws = list(watch_keywords)
        msg_lower = message.lower()
        for kw, ekleyen in kws:
            if kw.lower() in msg_lower:
                notify_master(
                    f"[ÝZLEME] [{self.server}] [{channel}] "
                    f"{sender}: {message}  (keyword: {kw})"
                )
                self._slog(f"[WATCH:{kw}] {channel} <{sender}> {message}")

    # ── Satýr iþleme ──────────────────────────────────────────────────────
    def handle_line(self, line: str):
        self._touch()
        parts = line.split()
        cmd   = parts[1] if len(parts) > 1 else ""

        # ── PING ──────────────────────────────────────────────────────────
        if line.startswith("PING"):
            token = line.split(":", 1)[1] if ":" in line else parts[1]
            self.send(f"PONG :{token}")
            return

        # ── PONG — kendi gönderdiðimiz PING'e cevap ───────────────────────
        if cmd == "PONG" or line.startswith("PONG"):
            self._last_pong    = time.time()
            self._ping_sent_at = None
            return

        # ── 001 Kayýt tamamlandý ──────────────────────────────────────────
        if cmd == "001":
            log.info(f"[{self.label}] Kayýt olundu.")
            self._slog(f"[CONNECT] {self.server}:{self.port}")
            if self.connected_at is None:
                self.connected_at = time.time()
            self.connect_history.appendleft(
                ("baðlandý", time.strftime("%H:%M:%S"))
            )
            self._set_status("baðlý")
            self._nick_registered    = False
            self.nick_status         = "unknown"
            self._register_retry_at  = None
            self._register_retry_sec = 0
            self._notified_disconnect = False
            self.channels.clear()
            self.msg_count = 0
            self.send(f"PRIVMSG NickServ :IDENTIFY {self.password}")
            time.sleep(1)
            self.send(f"JOIN {self.channel}")
            return

        # ── JOIN ──────────────────────────────────────────────────────────
        if cmd == "JOIN":
            joiner    = parts[0].split("!")[0].lstrip(":")
            joined_ch = (parts[2].lstrip(":") if len(parts) > 2 else "").strip()
            if joiner.lower() == self.nick.lower():
                self.channels.add(joined_ch)
                log.info(f"[{self.label}] Kanala katýldým: {joined_ch}")
            return

        # ── PART ──────────────────────────────────────────────────────────
        if cmd == "PART":
            leaver = parts[0].split("!")[0].lstrip(":")
            ch     = parts[2].lstrip(":") if len(parts) > 2 else ""
            if leaver.lower() == self.nick.lower():
                self.channels.discard(ch)
            return

        # ── KICK ──────────────────────────────────────────────────────────
        if cmd == "KICK":
            channel = parts[2] if len(parts) > 2 else ""
            kicked  = parts[3] if len(parts) > 3 else ""
            if kicked.lower() == self.nick.lower():
                self.channels.discard(channel)
                notify_master(f"âš* [{self.server}] Kanaldan atýldým: {channel}")
                self._slog(f"[KICKED] {channel}")
                if channel.lower() == self.channel.lower():
                    log.warning(f"[{self.label}] Ana kanaldan atýldým! 5 sn sonra yeniden katýlýyorum.")
                    time.sleep(5)
                    self.send(f"JOIN {self.channel}")
            return

        # ── 433 Nick kullanýmda ───────────────────────────────────────────
        if cmd == "433":
            log.warning(f"[{self.label}] Nick kullanýmda, GHOST deneniyor.")
            self._try_ghost()
            return

        # ── NICK deðiþikliði takibi ────────────────────────────────────────
        if cmd == "NICK":
            changer  = parts[0].split("!")[0].lstrip(":")
            new_nick = parts[2].lstrip(":") if len(parts) > 2 else ""
            # Birisi SLAVE_NICK'i býraktýysa al
            if new_nick.lower() == SLAVE_NICK.lower() and changer.lower() != self.nick.lower():
                log.info(f"[{self.label}] {SLAVE_NICK} serbest kaldý, alýnýyor.")
                self.send(f"NICK {SLAVE_NICK}")
                self.nick = SLAVE_NICK
            return

        # ── PRIVMSG ───────────────────────────────────────────────────────
        if cmd == "PRIVMSG":
            if len(parts) < 4:
                return
            prefix  = parts[0]
            sender  = prefix.split("!")[0].lstrip(":")
            target  = parts[2]
            message = " ".join(parts[3:]).lstrip(":")

            if target.lower() == self.nick.lower():
                # NickServ PRIVMSG
                if is_nickserv(prefix):
                    self._handle_nickserv(message.lower())
                    return
                # Gerçek PM
                with self.pm_lock:
                    self.pm_log.append((time.time(), sender, message))
                    if len(self.pm_log) > 20:
                        self.pm_log = self.pm_log[-20:]
                self.pm_count_total += 1
                log.info(f"[{self.label}] PM alýndý — {sender}: {message}")
                self._slog(f"[PM] <{sender}> {message}")
                notify_master(f"�� [{self.server}] PM — {sender}: {message}")
            else:
                # Kanal mesajý
                self.msg_count += 1
                self._slog(f"[{target}] <{sender}> {message}")
                self._check_watch(target, sender, message)
            return

        # ── NOTICE ────────────────────────────────────────────────────────
        if cmd == "NOTICE":
            if len(parts) < 4:
                return
            prefix = parts[0]
            body   = " ".join(parts[3:]).lstrip(":").lower()
            if is_nickserv(prefix):
                self._handle_nickserv(body)
            return

    # ── Aktif PING gönder ─────────────────────────────────────────────────
    def _ping_loop(self):
        """Arka planda PING gönder, PONG gelmezse reconnect yap."""
        while self.running:
            time.sleep(SLAVE_PING_INTERVAL)
            if not self.running:
                break
            if self.status != "baðlý":
                continue
            # PONG bekliyorsak ve süre aþtýysa
            if self._ping_sent_at:
                if time.time() - self._ping_sent_at > SLAVE_PING_TIMEOUT:
                    log.warning(f"[{self.label}] PONG alýnamadý, yeniden baðlanýlýyor.")
                    self._set_status("yeniden baðlanýyor", "pong timeout")
                    self.disconnect()
                    return
            else:
                try:
                    self._ping_sent_at = time.time()
                    self.send(f"PING :{self.server}")
                except Exception:
                    pass

    # ── Günlük rapor ─────────────────────────────────────────────────────
    def _check_daily_report(self):
        import datetime
        now  = datetime.datetime.now()
        today = now.date()
        if now.hour == DAILY_REPORT_HOUR:
            if self._last_daily_report != today:
                self._last_daily_report = today
                with self.pm_lock:
                    pm_c = len(self.pm_log)
                notify_master(
                    f"�� Günlük Rapor [{self.server}] — "
                    f"Uptime: {self._uptime_str()} | "
                    f"Mesaj: {self.msg_count} | "
                    f"PM: {self.pm_count_total} | "
                    f"Kanallar: {len(self.channels)} | "
                    f"Reconnect: {self.reconnects}x | "
                    f"NickServ: {self.nick_status}"
                )
                self.msg_count = 0   # Günlük sayacý sýfýrla

    # ── Detaylý durum raporu ──────────────────────────────────────────────
    def durum_detay(self) -> list:
        lines = []
        lines.append(f"┌─── {self.server}:{self.port} ───────────────────────")
        lines.append(
            f"│ Durum  : {self.status}"
            f"  │  Uptime: {self._uptime_str()}"
            f"  │  Idle: {self._idle_str()}"
        )
        if self.reconnects or self.last_error:
            hata = f"  │  Son hata: {self.last_error}" if self.last_error and self.status != "baðlý" else ""
            lines.append(f"│ Reconnect: {self.reconnects}x{hata}")

        # Baðlantý geçmiþi
        if self.connect_history:
            gecmis = " → ".join(f"{ev}@{zaman}" for ev, zaman in self.connect_history)
            lines.append(f"│ Geçmiþ : {gecmis}")

        # Nick / NickServ
        retry_str = ""
        if self._register_retry_at and self.nick_status == "not_registered":
            kalan = int(self._register_retry_at - time.time())
            if kalan > 0:
                retry_str = f" (retry: {kalan}sn kaldý)"
        nick_map = {
            "identified"    : "✔ Identify edildi",
            "registered"    : "✔ Register edildi (bu oturumda)",
            "not_registered": "✘ Kayýtlý deðil → register deneniyor",
            "wrong_password": "✘ Yanlýþ þifre",
            "unknown"       : "? Yanýt alýnamadý",
        }
        lines.append(
            f"│ Nick   : {self.nick}"
            f"  │  NickServ: {nick_map.get(self.nick_status, self.nick_status)}{retry_str}"
        )

        # Ýstatistikler
        lines.append(
            f"│ Mesaj  : {self.msg_count} (bugün)"
            f"  │  PM toplam: {self.pm_count_total}"
        )

        # Kanallar
        if self.channels:
            lines.append(f"│ Kanallar: {', '.join(sorted(self.channels))}")
        else:
            lines.append("│ Kanallar: (henüz hiçbir kanalda deðil)")

        # PM'ler
        with self.pm_lock:
            pm_copy = list(self.pm_log)
        if pm_copy:
            lines.append(f"│ PM ({len(pm_copy)} adet — son 5):")
            for ts, nick, msg in pm_copy[-5:]:
                zaman = time.strftime("%H:%M:%S", time.localtime(ts))
                lines.append(f"│   [{zaman}] {nick}: {msg}")
        else:
            lines.append("│ PM: yok")

        lines.append("└────────────────────────────────────────────────")
        return lines

    # ── Restart ───────────────────────────────────────────────────────────
    def restart(self):
        log.info(f"[{self.label}] Restart istendi.")
        self._restart_flag = True
        try:
            self.send("QUIT :Yeniden baðlanýlýyor...")
        except Exception:
            pass
        time.sleep(0.3)
        self.disconnect()

    # ── Ana döngü ─────────────────────────────────────────────────────────
    def run(self):
        key = f"{self.server}:{self.port}"
        log.info(f"[{self.label}] Slave bot baþlatýldý.")

        # PING loop thread
        threading.Thread(target=self._ping_loop, name=f"ping-{key}", daemon=True).start()

        while self.running:
            self._restart_flag = False
            try:
                self._set_status("baðlanýyor")
                self.connect()
                self.register()
                while self.running:
                    try:
                        for line in self.read_lines():
                            self.handle_line(line)
                        self._check_daily_report()
                        if self._restart_flag:
                            break
                    except socket.timeout:
                        log.warning(f"[{self.label}] Ping zaman aþýmý.")
                        self._set_status("yeniden baðlanýyor", "ping timeout")
                        break
                    except (ConnectionResetError, OSError) as e:
                        log.error(f"[{self.label}] Baðlantý hatasý: {e}")
                        self._set_status("yeniden baðlanýyor", str(e))
                        break
            except Exception as e:
                log.error(f"[{self.label}] Beklenmeyen hata: {e}")
                self._set_status("yeniden baðlanýyor", str(e))
            finally:
                self.disconnect()
                self.channels.clear()
                if self.running and not self._notified_disconnect:
                    self._notified_disconnect = True
                    self.connect_history.appendleft(
                        ("koptu", time.strftime("%H:%M:%S"))
                    )
                    notify_master(
                        f"âš* [{self.server}:{self.port}] Baðlantý koptu! "
                        f"{RECONNECT_DELAY}sn sonra yeniden baðlanýlacak."
                    )
                    self._slog(f"[DISCONNECT] yeniden baðlanýlýyor...")
                if self.running:
                    self.reconnects += 1
                    log.info(f"[{self.label}] {RECONNECT_DELAY} sn sonra yeniden baðlanýlacak...")
                    time.sleep(RECONNECT_DELAY)

        self._set_status("durduruldu")
        with slave_lock:
            slave_bots.pop(key, None)
        log.info(f"[{self.label}] Slave bot durduruldu.")


# ══════════════════════════════════════════════════════════════════════════════
#  ANA BOT (BncBot)
# ══════════════════════════════════════════════════════════════════════════════
class MasterBot(IRCConnection):
    def __init__(self):
        super().__init__(
            MASTER_SERVER, MASTER_PORT,
            MASTER_NICK, MASTER_PASSWORD,
            MASTER_CHANNEL, MASTER_IDENT, MASTER_REALNAME,
            label="Master:BncBot"
        )
        self._oper_done = False

    def do_oper(self):
        if not self._oper_done:
            log.info(f"[Master] OPER giriþi: {OPER_NAME}")
            self.send(f"OPER {OPER_NAME} {OPER_PASSWORD}")

    def _start_slave(self, host: str, port: int):
        bot = SlaveBot(host, port)
        key = f"{host}:{port}"
        with slave_lock:
            slave_bots[key] = bot
        threading.Thread(target=bot.run, name=f"slave-{key}", daemon=True).start()
        return bot

    def handle_line(self, line: str):
        parts = line.split()
        cmd   = parts[1] if len(parts) > 1 else ""

        if line.startswith("PING"):
            token = line.split(":", 1)[1] if ":" in line else parts[1]
            self.send(f"PONG :{token}")
            return

        if cmd == "001":
            log.info("[Master] Kayýt olundu.")
            self.send(f"PRIVMSG NickServ :IDENTIFY {self.password}")
            time.sleep(1)
            self.do_oper()
            time.sleep(1)
            self.send(f"JOIN {self.channel}")
            self._restore_servers()
            return

        if cmd == "JOIN":
            joiner    = parts[0].split("!")[0].lstrip(":")
            joined_ch = parts[2].lstrip(":") if len(parts) > 2 else ""
            if joiner.lower() == self.nick.lower():
                if joined_ch.lower() == self.channel.lower():
                    if not self._joined:
                        self._joined = True
                        log.info(f"[Master] '{self.channel}' kanalýna katýldým.")
                else:
                    self.send(f"PART {joined_ch}")
            return

        if cmd == "381":
            self._oper_done = True
            log.info("[Master] OPER giriþi baþarýlý! (Eggdrop)")
            return

        if cmd == "491":
            log.warning("[Master] OPER baþarýsýz! (491)")
            return

        if cmd == "433":
            self.send(f"NICK {self.nick}_")
            return

        if cmd == "KICK":
            channel = parts[2] if len(parts) > 2 else ""
            kicked  = parts[3] if len(parts) > 3 else ""
            if kicked.lower() == self.nick.lower() and channel.lower() == self.channel.lower():
                time.sleep(5)
                self.send(f"JOIN {self.channel}")
            return

        if cmd == "NOTICE":
            body   = " ".join(parts[3:]).lower()
            sender = parts[0].split("!")[0].lstrip(":").lower()
            if sender == "nickserv" and "identify" in body:
                self.send(f"PRIVMSG NickServ :IDENTIFY {self.password}")
            return

        if cmd == "PRIVMSG":
            if len(parts) < 4:
                return
            sender    = parts[0].split("!")[0].lstrip(":")
            target    = parts[2]
            message   = " ".join(parts[3:]).lstrip(":")
            reply     = target if target.startswith("#") else sender
            msg_lower = message.strip().lower()

            if msg_lower.startswith("!ekle "):
                self._cmd_ekle(sender, reply, message.strip()[6:].strip())
            elif msg_lower.startswith("!sil "):
                self._cmd_sil(sender, reply, message.strip()[5:].strip())
            elif msg_lower.startswith("!restart "):
                self._cmd_restart(sender, reply, message.strip()[9:].strip())
            elif msg_lower == "!restartall":
                self._cmd_restartall(sender, reply)
            elif msg_lower.startswith("!izle "):
                self._cmd_izle(sender, reply, message.strip()[6:].strip())
            elif msg_lower.startswith("!izlesil "):
                self._cmd_izlesil(sender, reply, message.strip()[9:].strip())
            elif msg_lower == "!izlelist":
                self._cmd_izlelist(reply)
            elif msg_lower.startswith("!pmtemizle "):
                self._cmd_pmtemizle(sender, reply, message.strip()[11:].strip())
            elif msg_lower.startswith("!log "):
                self._cmd_log(sender, reply, message.strip()[5:].strip())
            elif msg_lower == "!liste":
                self._cmd_liste(reply)
            elif msg_lower == "!durum":
                self._cmd_durum(reply)
            elif msg_lower == "!yardim":
                self._cmd_yardim(reply)

    # ── Komutlar ──────────────────────────────────────────────────────────
    def _parse_host_port(self, arg: str):
        p    = arg.split(":")
        host = p[0].strip()
        try:
            port = int(p[1]) if len(p) > 1 else SLAVE_PORT
        except ValueError:
            port = SLAVE_PORT
        return host, port

    def _yetkili(self, requester, target) -> bool:
        if BOT_OWNER and requester.lower() != BOT_OWNER.lower():
            self.send(f"PRIVMSG {target} :Yetkisiz iþlem.")
            return False
        return True

    def _cmd_ekle(self, requester, target, arg):
        if not self._yetkili(requester, target): return
        host, port = self._parse_host_port(arg)
        if not host:
            self.send(f"PRIVMSG {target} :Kullaným: !ekle irc.sunucu.com[:port]")
            return
        key = f"{host}:{port}"
        with slave_lock:
            if key in slave_bots:
                self.send(f"PRIVMSG {target} :Zaten baðlý: {key}")
                return
        self._start_slave(host, port)
        db_save()
        self.send(f"PRIVMSG {target} :Baðlanýlýyor → {key}")

    def _cmd_sil(self, requester, target, arg):
        if not self._yetkili(requester, target): return
        host, port = self._parse_host_port(arg)
        key = f"{host}:{port}"
        with slave_lock:
            bot = slave_bots.get(key)
        if bot:
            bot.stop()
            db_remove(host, port)
            self.send(f"PRIVMSG {target} :{key} → durduruldu ve silindi.")
        else:
            with slave_lock:
                aktif = list(slave_bots.keys())
            self.send(f"PRIVMSG {target} :Bulunamadý: {key}")
            if aktif:
                self.send(f"PRIVMSG {target} :Aktif: {', '.join(aktif)}")

    def _cmd_restart(self, requester, target, arg):
        if not self._yetkili(requester, target): return
        host, port = self._parse_host_port(arg)
        key = f"{host}:{port}"
        with slave_lock:
            bot = slave_bots.get(key)
        if bot:
            bot.restart()
            self.send(f"PRIVMSG {target} :{key} → yeniden baðlanýlýyor...")
        else:
            with slave_lock:
                aktif = list(slave_bots.keys())
            self.send(f"PRIVMSG {target} :Bulunamadý: {key}")
            if aktif:
                self.send(f"PRIVMSG {target} :Aktif: {', '.join(aktif)}")

    def _cmd_restartall(self, requester, target):
        """Tüm slave'leri sýrayla yeniden baðlat."""
        if not self._yetkili(requester, target): return
        with slave_lock:
            bots = list(slave_bots.values())
        if not bots:
            self.send(f"PRIVMSG {target} :Aktif slave bot yok.")
            return
        self.send(f"PRIVMSG {target} :{len(bots)} slave yeniden baþlatýlýyor...")
        def _do_restartall():
            for bot in bots:
                bot.restart()
                time.sleep(3)
        threading.Thread(target=_do_restartall, daemon=True).start()

    def _cmd_izle(self, requester, target, keyword):
        """!izle <keyword> — Kanalda bu kelime geçince bildirim al."""
        if not self._yetkili(requester, target): return
        if not keyword:
            self.send(f"PRIVMSG {target} :Kullaným: !izle <keyword>")
            return
        with watch_lock:
            mevcut = [k for k, _ in watch_keywords]
            if keyword.lower() in [k.lower() for k in mevcut]:
                self.send(f"PRIVMSG {target} :Zaten izleniyor: {keyword}")
                return
            watch_keywords.append((keyword, requester))
        self.send(f"PRIVMSG {target} :Ýzlemeye alýndý: {keyword}")

    def _cmd_izlesil(self, requester, target, keyword):
        """!izlesil <keyword> — Ýzleme listesinden çýkar."""
        if not self._yetkili(requester, target): return
        with watch_lock:
            before = len(watch_keywords)
            watch_keywords[:] = [(k, n) for k, n in watch_keywords
                                  if k.lower() != keyword.lower()]
            after = len(watch_keywords)
        if before != after:
            self.send(f"PRIVMSG {target} :Ýzlemeden çýkarýldý: {keyword}")
        else:
            self.send(f"PRIVMSG {target} :Bulunamadý: {keyword}")

    def _cmd_izlelist(self, target):
        """!izlelist — Aktif keyword listesi."""
        with watch_lock:
            kws = list(watch_keywords)
        if kws:
            liste = ", ".join(f"{k} ({n})" for k, n in kws)
            self.send(f"PRIVMSG {target} :Ýzlenen ({len(kws)}): {liste}")
        else:
            self.send(f"PRIVMSG {target} :Ýzleme listesi boþ.")

    def _cmd_pmtemizle(self, requester, target, arg):
        """!pmtemizle irc.sunucu.com — O sunucunun PM logunu sýfýrla."""
        if not self._yetkili(requester, target): return
        host, port = self._parse_host_port(arg)
        key = f"{host}:{port}"
        with slave_lock:
            bot = slave_bots.get(key)
        if bot:
            with bot.pm_lock:
                bot.pm_log.clear()
            self.send(f"PRIVMSG {target} :{key} PM logu temizlendi.")
        else:
            self.send(f"PRIVMSG {target} :Bulunamadý: {key}")

    def _cmd_log(self, requester, target, arg):
        """!log irc.sunucu.com — Son 10 log satýrýný kanala yaz."""
        if not self._yetkili(requester, target): return
        host, port = self._parse_host_port(arg)
        name = host.replace(".", "_")
        log_file = os.path.join(LOG_DIR, f"{name}.log")
        if not os.path.exists(log_file):
            self.send(f"PRIVMSG {target} :Log dosyasý bulunamadý: {host}")
            return
        try:
            with open(log_file, "r", encoding="utf-8", errors="replace") as f:
                satirlar = f.readlines()
            son10 = satirlar[-10:]
            self.send(f"PRIVMSG {target} :── Son 10 log [{host}] ──")
            for s in son10:
                self.send(f"PRIVMSG {target} :{s.rstrip()}")
                time.sleep(0.05)
        except Exception as e:
            self.send(f"PRIVMSG {target} :Log okunamadý: {e}")

    def _cmd_liste(self, target):
        with slave_lock:
            keys = list(slave_bots.keys())
        if keys:
            self.send(f"PRIVMSG {target} :Aktif ({len(keys)}): {', '.join(keys)}")
        else:
            self.send(f"PRIVMSG {target} :Aktif slave bot yok.")

    def _cmd_durum(self, target):
        with slave_lock:
            bots = list(slave_bots.values())
        if not bots:
            self.send(f"PRIVMSG {target} :Aktif slave bot yok.")
            return
        for bot in bots:
            for satir in bot.durum_detay():
                self.send(f"PRIVMSG {target} :{satir}")
                time.sleep(0.05)

    def _cmd_yardim(self, target):
        komutlar = [
            "!ekle irc.sunucu.com[:port]    — Sunucuya slave baðla",
            "!sil irc.sunucu.com[:port]     — Slave'i durdur ve sil",
            "!restart irc.sunucu.com[:port] — Slave'i yeniden baðlat",
            "!restartall                    — Tüm slave'leri yeniden baðlat",
            "!liste                         — Aktif slave listesi",
            "!durum                         — Her slave'in detaylý durumu",
            "!izle <keyword>                — Kanalda kelime geçince bildirim",
            "!izlesil <keyword>             — Ýzlemeyi kaldýr",
            "!izlelist                      — Ýzlenen keyword listesi",
            "!pmtemizle irc.sunucu.com      — PM logunu sýfýrla",
            "!log irc.sunucu.com            — Son 10 log satýrý",
        ]
        for c in komutlar:
            self.send(f"PRIVMSG {target} :{c}")
            time.sleep(0.05)

    def _restore_servers(self):
        entries = db_load()
        if not entries:
            return
        log.info(f"[Master] {len(entries)} kayýtlý sunucu yükleniyor...")
        for e in entries:
            host = e.get("host", "")
            port = e.get("port", SLAVE_PORT)
            key  = f"{host}:{port}"
            with slave_lock:
                if key in slave_bots:
                    continue
            self._start_slave(host, port)
            log.info(f"[Master] Otomatik baþlatýldý: {key}")
            time.sleep(1)

    def run(self):
        global master_ref
        master_ref = self
        log.info("[Master] Ana bot baþlatýlýyor...")
        while self.running:
            self._oper_done = False
            self._joined    = False
            try:
                self.connect()
                self.register()
                while self.running:
                    try:
                        for line in self.read_lines():
                            self.handle_line(line)
                    except socket.timeout:
                        log.warning("[Master] Ping zaman aþýmý.")
                        break
                    except (ConnectionResetError, OSError) as e:
                        log.error(f"[Master] Baðlantý hatasý: {e}")
                        break
            except Exception as e:
                log.error(f"[Master] Beklenmeyen hata: {e}")
            finally:
                self.disconnect()
                if self.running:
                    log.info(f"[Master] {RECONNECT_DELAY} sn sonra yeniden baðlanýlacak...")
                    time.sleep(RECONNECT_DELAY)


# ══════════════════════════════════════════════════════════════════════════════
if __name__ == "__main__":
    master = MasterBot()
    try:
        master.run()
    except KeyboardInterrupt:
        log.info("Kapatýlýyor...")
        master.stop()
        with slave_lock:
            for bot in list(slave_bots.values()):
                bot.stop()
        log.info("Tüm botlar durduruldu.")
 
 

Yer Ýmleri


Þu anda bu konuyu görüntüleyen etkin kullanýcýlar: 1 (0 üye ve 1 konuk)
 

Yayýnlama Kurallarý


Forum saati GMT +3 olarak ayarlanmýþtýr. Þu an saat: 01:17

Forum
Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2026, vBulletin Solutions Inc.
IRCdForum.Net, lisanslý vBulletin® kullanmaktadýr.
Yasal Uyarý
IRCdForum.Net; 5651 sayýlý kanuna göre yer saðlayýcý bir forum sitesidir. Dolayýsýyla forumdaki içeriklerden ilgili içeriði paylaþan üyeler sorumludur. Hukuka aykýrý içerik bildirimleri için ÝLETÝÞÝM linkinden bildirim gönderebilirsiniz.


güzel hosting

IRCdForum.Net; altyapý gücünü Güzel Hosting'den alýr.