1- from os import path
21from socket import *
3- from glob import glob
2+ from time import sleep
43from select import select
54from .config import Config
65from threading import Thread
7- from .webserver import WebServer
8- from xml .etree .ElementTree import fromstring
96
107class Client :
11- def __init__ (self ):
12- self .Threads = []
13- self .WebServer = WebServer ()
14- self .RunServer = Thread (target = self .WebServer .start )
15- self .RunServer .daemon = True
16- self .RunServer .start ()
17- print ("> Webserver started." )
18- self .Plugins = []
19- self .loadPlugins ()
20- print ("> Plugins started." )
21- self .RunSocket = Thread (target = self .createSocket )
22- self .RunSocket .daemon = True
23- self .RunSocket .start ()
24- print ("> Socket started." )
25-
26- def createSocket (self ):
8+ def __init__ (self , server , sock ):
279 try :
28- xSock = socket (AF_INET , SOCK_STREAM )
29- xSock .bind ((Config .CLIENT_SERVERIP , Config .CLIENT_SERVERPORT ))
30- while True :
31- xSock .listen (1 )
32- (conn , (ip , port )) = xSock .accept ()
33- thread = Thread (target = self .addClient , args = (conn ,))
34- thread .start ()
35- self .Threads .append (thread )
36- for t in self .Threads :
37- t .join ()
10+ self .isConnected = False
11+ self .server = server
12+ self .socks = [[], []]
13+ self .users = {}
14+ self .userID = 0
15+ self .rank = 0
16+ self .chatID = 0
17+ self .socks [1 ] = sock
18+ self .connectToXat ()
3819 except :
3920 pass
4021
41- def parsePlugins (self , packet , direction , sock ):
42- for p in self .Plugins :
43- exec (p , globals ())
44- data = plugin (self , packet , direction , sock )
45- if data :
46- packet = data
47- return packet
22+ def connectToXat (self ):
23+ self .socks [0 ] = socket (AF_INET , SOCK_STREAM , SOL_TCP )
24+ self .socks [0 ].connect ((Config .XAT_IP , Config .XAT_PORT ))
25+ self .startHeartBeat ()
26+ self .keepRunning ()
4827
49- def xml2Array (self , xml ):
50- try :
51- returnArray = {}
52- xml = xml .strip ('\0 ' )
53- xml = fromstring (xml )
54- returnArray ['name' ] = xml .tag
55- for tag , attrib in xml .attrib .items ():
56- returnArray [tag ] = attrib
57- except :
58- pass
59- return returnArray
60-
61- def buildPacket (self , node , packets ):
62- packet = ["<" + node ]
63- for (k , v ) in packets .items ():
64- if str (k ) != 'name' :
65- packet .append (str (k ) + "=\" " + str (v ) + "\" " )
66- packet .append ("/>" )
67- return (' ' .join (packet ) + '\x00 ' ).encode ()
68-
69- def fixUserID (self , uid ):
70- uid += "_"
71- trim = uid .index ('_' )
72- return uid [0 :trim ]
73-
74- def loadPlugins (self ):
75- self .Plugins = []
76- for pname in glob ('plugins/*.py' ):
77- self .Plugins .append (open (pname ).read ())
78-
79- def Logger (self , file , text ):
80- if path .exists ('logs/' + file + '.log' ):
81- logs = open ('logs/' + file + '.log' , 'a+' )
82- logs .write (text + "\n " )
83- logs .close ()
84-
85- def addClient (self , conn ):
86- socks = [[], []]
87- socks [0 ] = socket (AF_INET , SOCK_STREAM , SOL_TCP )
88- socks [0 ].connect ((Config .XAT_IP , Config .XAT_PORT ))
89- socks [0 ].setblocking (0 )
90- socks [1 ] = conn
28+ def keepRunning (self ):
9129 try :
9230 while True :
93- allSocks ,_ ,_ = select (socks , [], [])
94- for sock in allSocks :
31+ socks ,_ ,_ = select (self . socks , [], [])
32+ for sock in socks :
9533 recv = ""
34+ sock .setblocking (0 )
9635 while recv [- 1 :] != chr (0 ):
97- recv += sock .recv (1204 ).decode ('utf-8' , 'ignore' )
98- if len (recv ) <= 1 :
36+ recv += sock .recv (2048 ).decode ('utf-8' , 'ignore' )
37+ if len (recv ) < 1 :
38+ self .killSockets ()
9939 break
10040 if recv :
10141 for packet in recv .split ('\x00 ' ):
10242 if '<f ' in packet :
103- dataInfo = 1 if sock == socks [0 ] else 0
104- socks [dataInfo ].send ((packet + '\x00 ' ). encode ( ))
43+ dataInfo = 1 if sock == self . socks [0 ] else 0
44+ self . socks [dataInfo ].send (bytes (packet + '\x00 ' , encoding = 'utf-8' ))
10545 else :
106- data = self .xml2Array (packet )
107- if data :
108- dataInfo = [1 , 'fromxat' , 'RECV' ] if sock == socks [0 ] else [0 , 'toxat' , 'SENT' ]
109- data = self .parsePlugins (data , dataInfo [1 ], conn )
110- toBeSend = self .buildPacket (data ['name' ], data )
111- if data ['name' ] == 'policy-file-request' :
112- socks [1 ].send (Config .CROSSDOMAIN .encode () + b'\x00 ' )
113- elif data ['name' ] != 'HIDDEN' :
114- print ('[' + dataInfo [2 ] + ']: ' , toBeSend .decode ('utf-8' , 'ignore' ))
115- socks [dataInfo [0 ]].send (toBeSend )
116-
117- except Exception as e :
118- error = str (e )
119- if not 'ConnectionAbortedError' in error and not '10053' in error :
120- self .Logger ('errors' , error )
46+ self .parse (sock , packet )
47+ except :
48+ self .killSockets ()
49+
50+ def parse (self , sock , packet ):
51+ data = self .server .xml2Array (packet )
52+ if not data :
53+ return
54+ dataInfo = [1 , 'fromxat' , 'RECV' ] if sock == self .socks [0 ] else [0 , 'toxat' , 'SENT' ]
55+ data = self .server .parsePlugins (data , dataInfo [1 ], self )
56+ if data ['name' ] == 'policy-file-request' :
57+ self .sendToUser (Config .CROSSDOMAIN )
58+ elif data ['name' ] != 'HIDDEN' :
59+ if data ['name' ] == 'j2' :
60+ self .userID = int (data ['u' ])
61+ self .chatID = int (data ['c' ])
62+ elif data ['name' ] == 'i' and 'r' in data :
63+ self .rank = int (data ['r' ])
64+ elif data ['name' ] == 'l' and 'u' in data :
65+ if int (data ['u' ]) in self .users :
66+ del self .users [int (data ['u' ])]
67+ elif data ['name' ] == 'done' :
68+ self .isConnected = True
69+ self .announce ('xatClient is running...' )
70+ elif data ['name' ] == 'u' and 'u' in data :
71+ self .users [int (data ['u' ])] = {
72+ 'name' : data ['n' ],
73+ 'avatar' : data ['a' ],
74+ 'home' : data ['h' ],
75+ 'rank' : int (data ['f' ]) & 7 if 'f' in data else 5 ,
76+ 'reg' : data ['N' ] if 'N' in data else False ,
77+ 'd0' : data ['d0' ] if 'd0' in data else False ,
78+ 'd2' : data ['d2' ] if 'd2' in data else False ,
79+ 'f' : data ['f' ] if 'f' in data else False ,
80+ }
81+ toBeSend = self .server .buildPacket (data ['name' ], data )
82+ print ('[' + dataInfo [2 ] + ' - ' + str (self .chatID ) + ']: ' , toBeSend )
83+ self .socks [dataInfo [0 ]].send (bytes (toBeSend , encoding = 'utf-8' ))
84+
85+ def sendToUser (self , packet ):
86+ print ('[RECV - ' + str (self .chatID ) + ']: ' , packet )
87+ return self .socks [1 ].send (bytes (packet + '\x00 ' , encoding = 'utf-8' ))
88+
89+ def sendToXat (self , packet ):
90+ print ('[SENT - ' + str (self .chatID ) + ']: ' , packet )
91+ return self .socks [0 ].send (bytes (packet + '\x00 ' , encoding = 'utf-8' ))
92+
93+ def announce (self , message ):
94+ self .sendToUser (self .server .buildPacket ('m' , {'t' : message , 'u' : 0 }))
95+
96+ def killSockets (self ):
97+ for sock in self .socks :
98+ sock .close ()
99+
100+ def sendHeartBeat (self ):
101+ try :
102+ sleep (10 ) # first time only
103+ while True :
104+ if self .isConnected :
105+ self .sendToXat (self .server .buildPacket ('c' , {'u' : self .userID , 't' : '/KEEPALIVE' }))
106+ sleep (50 )
107+ except :
108+ pass
109+
110+
111+ def startHeartBeat (self ):
112+ thread = Thread (target = self .sendHeartBeat )
113+ thread .daemon = True
114+ thread .start ()
115+
116+ def getById (self , userid ):
117+ if not self .users :
118+ return False
119+ for uid , user in self .users .items ():
120+ if userid == uid :
121+ return user
122+ return False
0 commit comments