Python Forum
Issues in Chat App for Local Network
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Issues in Chat App for Local Network
#3
(Jul-19-2019, 04:11 AM)micseydel Wrote: I'd be interested in helping if you can reproduce the problem with fewer lines of code (I'm thinking 10-20 tops) and only necessary imports.

Ahh, I'm really sorry, i forgot to check back after no one replied initially. Anyways I found the problem myself, i.e. human errors, while reviewing. I took the project a little further with some more features then abandoned it after i got bored and started new projects @.@

The final (at the time) code is as below for anyone interested.

from PyQt5 import QtWidgets
import sys
import socket
import threading
import ipaddress
import time
import pickle


class MainWindow(QtWidgets.QWidget):

    def __init__(self):
        super(MainWindow, self).__init__()

        self.service = ""
        self.server = socket.socket()
        self.client = socket.socket()
        self.machineIP = socket.gethostbyname(socket.gethostname())
        self.isconnected = ""
        self.connectedusers = []
        self.unreadcount = 0
        self.oldtime = time.time()

        self.chatwindow = QtWidgets.QListWidget()
        self.userwindow = QtWidgets.QListWidget()
        self.typingfield = QtWidgets.QLineEdit()
        self.typingfield.returnPressed.connect(self.sendpressed)
        self.sendbutton = QtWidgets.QPushButton("Send")
        self.sendbutton.clicked.connect(self.sendpressed)

        self.tray_icon = QtWidgets.QSystemTrayIcon(self)
        self.tray_icon.activated.connect(self.onTrayIconActivated)
        self.tray_icon.setIcon(self.style().standardIcon(QtWidgets.QStyle.SP_ComputerIcon))

        show_action = QtWidgets.QAction("Show", self)
        quit_action = QtWidgets.QAction("Exit", self)
        show_action.triggered.connect(self.show)
        quit_action.triggered.connect(self.shutdownapp)
        tray_menu = QtWidgets.QMenu()
        tray_menu.addAction(show_action)
        tray_menu.addAction(quit_action)
        self.tray_icon.setContextMenu(tray_menu)
        self.tray_icon.show()

        self.setupUI()
        self.show()

    def closeEvent(self, event):
        if self.service == "server":
            event.ignore()
            self.hide()
            self.tray_icon.showMessage(
                "TAG IM",
                "App Minimized (Running as Host)",
                QtWidgets.QSystemTrayIcon.Information,
                1000)
        elif self.service == "client":
            event.ignore()
            self.hide()
            self.tray_icon.showMessage(
                "TAG IM",
                "App Minimized (Running as Client)",
                QtWidgets.QSystemTrayIcon.Information,
                1000)

    def shutdownapp(self):
        if self.service == "server":
            self.service == ""
            self.broadcast("Host has shutdown")
            self.server.close()
            app.quit()
        elif self.service == "client":
            self.service == ""
            message = "Left the chat"
            self.client.send(message.encode())
            self.client.close()
            print("Client closed manually")
            app.quit()
        elif self.service == "":
            app.quit()

    def onTrayIconActivated(self, reason):
        if reason == QtWidgets.QSystemTrayIcon.Trigger:
            self.show()
            self.focusWidget()

    def setupUI(self):
        mainlayout = QtWidgets.QVBoxLayout()
        displaybox = QtWidgets.QHBoxLayout()
        userlist = QtWidgets.QVBoxLayout()
        userlist.addWidget(QtWidgets.QLabel("Users Connected:"))
        userlist.addWidget(self.userwindow)
        displaybox.addWidget(self.chatwindow, 3)
        displaybox.addLayout(userlist, 1)
        inputbox = QtWidgets.QHBoxLayout()
        inputbox.addWidget(self.typingfield)
        inputbox.addWidget(self.sendbutton)
        mainlayout.addLayout(displaybox)
        mainlayout.addLayout(inputbox)
        self.setLayout(mainlayout)
        self.chatwindow.addItem("/host to setup server on local host (Port 7000)")
        self.chatwindow.addItem("/[email protected] to connect to server on local host (Port 7000)")
        self.chatwindow.scrollToBottom()

        self.typingfield.setFocus()
        self.setWindowTitle("TAG CHAT")

    def sendpressed(self):
        typedtext = self.typingfield.text()
        if typedtext:
            if typedtext[0] == "/":
                self.metaprocessor(typedtext)
            else:
                if self.service:
                    if self.service == "server":
                        self.broadcast(typedtext)
                    elif self.service == "client":
                        self.client.send(typedtext.encode())
                else:
                    self.chatwindow.addItem("Not connected to any group.")
                    self.chatwindow.scrollToBottom()
        self.typingfield.clear()
        self.typingfield.setFocus()

    def metaprocessor(self, typedtext):
        if typedtext == "/host":
            serverstart = threading.Thread(target=self.makeserver, args=())
            serverstart.daemon = True
            serverstart.start()
        elif typedtext[0:9] == "/connect@" and len(typedtext) > 9:
            userip = typedtext[9:]
            try:
                ipaddress.ip_address(userip)
                clientstart = threading.Thread(target=self.startclient, args=(userip, 7000))
                clientstart.daemon = True
                clientstart.start()
            except ValueError:
                self.chatwindow.addItem("Invalid IP address provided '" + userip + "'")
                self.chatwindow.scrollToBottom()
        elif typedtext == "/quit":
            self.shutdownapp()

        else:
            self.chatwindow.addItem("Invalid syntax")
            self.chatwindow.scrollToBottom()

    def startclient(self, serverip, port):
        self.client.connect((str(serverip), port))
        self.service = "client"
        while True:
            try:
                message = self.client.recv(4096)
                if message[0:10] == "~connected".encode():
                    connectedusers = pickle.loads(message[10:])
                    self.updateclientlistclient(connectedusers)
                else:
                    self.unreadnotification()
                    self.chatwindow.addItem(message.decode())
                    self.chatwindow.scrollToBottom()
            except:
                self.chatwindow.addItem("Host has closed the connection".decode())
                self.chatwindow.scrollToBottom()
                self.userwindow.clear()
                self.service = ""
                break

    def makeserver(self):
        self.chatwindow.addItem("Creating server @ " + self.machineIP + ":7000")
        self.server.bind((self.machineIP, 7000))
        self.chatwindow.addItem("Server started successfully...\nListening to all connections")
        self.chatwindow.scrollToBottom()
        self.service = "server"
        self.server.listen(100)
        while True:
            conn, addr = self.server.accept()
            message = "Connected to " + self.machineIP + ":7000"
            conn.send(message.encode())
            self.connectedusers.append((conn, addr))
            self.updateclientlistserver(self.connectedusers)
            newconnection = threading.Thread(target=self.startconnection, args=(conn, addr))
            newconnection.daemon = True
            newconnection.start()

    def startconnection(self, conn, addr):
        self.chatwindow.addItem("User " + str(addr) + " has joined the group.")
        self.chatwindow.scrollToBottom()
        while True:
            try:
                data = conn.recv(4096)
                self.unreadnotification()
                self.broadcast(data.decode())
            except:
                print("Client closing caught by server")
                conn.close()
                self.connectedusers.remove((conn, addr))
                self.updateclientlistserver(self.connectedusers)
                break

    def updateclientlistserver(self, connectedusers):
        self.userwindow.clear()
        for each in connectedusers:
            self.userwindow.addItem(each[1][0])

    def updateclientlistclient(self, connectedusers):
        self.userwindow.clear()
        for each in connectedusers:
            self.userwindow.addItem(each)

    def broadcast(self, typedtext):
        servermessage = self.machineIP + " : " + str(typedtext)
        self.chatwindow.addItem(servermessage)
        self.chatwindow.scrollToBottom()
        for each in self.connectedusers:
            message = each[1][0] + " : " + str(typedtext)
            each[0].send(message.encode())
            iplist = []
            for ips in self.connectedusers:
                iplist.append(ips[1][0])
            data = pickle.dumps(iplist)
            each[0].send("~connected".encode() + data)

    def unreadnotification(self):
        if not self.isVisible():
            self.unreadcount += 1
            if time.time() - self.oldtime > 60:
                self.oldtime = time.time()
                self.tray_icon.showMessage(
                    "TAG IM",
                    str(self.unreadcount) + " messages unread",
                    QtWidgets.QSystemTrayIcon.Information,
                    1000)
        else:
            self.unreadcount = 0


if __name__ == "__main__":

    # Back up the reference to the exceptionhook
    sys._excepthook = sys.excepthook


    def my_exception_hook(exctype, value, traceback):
        # Print the error and traceback
        print(exctype, value, traceback)
        # Call the normal Exception hook after
        sys._excepthook(exctype, value, traceback)
        sys.exit(1)


    # Set the exception hook to our wrapping function
    sys.excepthook = my_exception_hook

    app = QtWidgets.QApplication(sys.argv)
    mainApplication = MainWindow()

    try:
        sys.exit(app.exec_())
    except:
        print("Exiting")
Reply


Messages In This Thread
Issues in Chat App for Local Network - by iMuny - Jul-17-2019, 01:11 PM
RE: Issues in Chat App for Local Network - by iMuny - Aug-19-2019, 10:25 AM

Possibly Related Threads…
Thread Author Replies Views Last Post
  Chat box locking up with multiple clients running Clunk_Head 1 1,994 Nov-27-2019, 04:13 PM
Last Post: Clunk_Head
  How to restart another PC on the local network? Kundan 1 2,161 Sep-21-2019, 11:31 AM
Last Post: ThomasL
  Chat (Client-Server) andresdrr 3 3,786 Aug-26-2019, 02:01 PM
Last Post: ThomasL

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020