forked from aewens/abots
Changed file permissions, cleaned up socket_server and added new features
This commit is contained in:
parent
8df62cdc01
commit
54f4eda307
|
@ -1,22 +1,34 @@
|
||||||
* net
|
## net
|
||||||
* socket_server
|
|
||||||
* Add comments
|
|
||||||
* Abstract default handler out to another file
|
|
||||||
* Send heartbeat
|
|
||||||
* Better handle clients disconnecting
|
|
||||||
* Remove lookup, use clients instead
|
|
||||||
* Add alias system for clients to replace using fd
|
|
||||||
* Add support for cryptography
|
|
||||||
* socket_client
|
|
||||||
* Add comments
|
|
||||||
* Abstract default handler out to another file
|
|
||||||
* Respond to heartbeat
|
|
||||||
* Respond to alias from server
|
|
||||||
* Add support for cryptography
|
|
||||||
|
|
||||||
* Add crypto set
|
### socket_server
|
||||||
* In crypto add GPG, Diffie-Hellman, and symmetric & asymmetric crypto
|
|
||||||
* Add helpers set
|
- [ ] Add comments
|
||||||
* In helpers add JSON encoding / decoding
|
- [ ] Abstract default handler out to another file
|
||||||
* Add db set
|
- [ ] Send heartbeat
|
||||||
* In db add sqlite wrappers
|
- [ ] Better handle clients disconnecting
|
||||||
|
- [ ] Remove lookup, use clients instead
|
||||||
|
- [ ] Add alias system for clients to replace using fd
|
||||||
|
- [ ] Add support for cryptography
|
||||||
|
|
||||||
|
### socket_client
|
||||||
|
|
||||||
|
- [ ] Add comments
|
||||||
|
- [ ] Abstract default handler out to another file
|
||||||
|
- [ ] Respond to heartbeat
|
||||||
|
- [ ] Respond to alias from server
|
||||||
|
- [ ] Add support for cryptography
|
||||||
|
|
||||||
|
## crypto
|
||||||
|
|
||||||
|
- [ ] Add crypto set
|
||||||
|
- [ ] In crypto add GPG, Diffie-Hellman, and symmetric & asymmetric crypto
|
||||||
|
|
||||||
|
## helpers
|
||||||
|
|
||||||
|
- [ ] Add helpers set
|
||||||
|
- [ ] In helpers add JSON encoding / decoding
|
||||||
|
|
||||||
|
## db
|
||||||
|
|
||||||
|
- [ ] Add db set
|
||||||
|
- [ ] In db add sqlite wrappers
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
from abots.net.socket_server import SocketServer
|
from abots.net.socket_server import SocketServer
|
||||||
from abots.net.socket_client import SocketClient
|
from abots.net.socket_client import SocketClient
|
||||||
|
from abots.net.socket_server_handler import SocketServerHandler
|
|
@ -1,5 +1,5 @@
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
from multiprocessing import Process, JoinableQueue, Queue
|
from multiprocessing import Process, Queue, JoinableQueue
|
||||||
from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
|
from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
|
||||||
|
|
||||||
class SocketClient(Process):
|
class SocketClient(Process):
|
||||||
|
@ -70,11 +70,11 @@ class SocketClient(Process):
|
||||||
except OSError:
|
except OSError:
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
def _gather_messages(self):
|
def _process_inbox(self):
|
||||||
data = self._get_message()
|
while not self.inbox.empty():
|
||||||
if data is None:
|
message, args = self.inbox.get()
|
||||||
return None
|
self._send_message(message, *args)
|
||||||
self.outbox.put(self.handler(data))
|
self.inbox.task_done()
|
||||||
|
|
||||||
def _prepare(self):
|
def _prepare(self):
|
||||||
self.sock.setblocking(False)
|
self.sock.setblocking(False)
|
||||||
|
@ -101,14 +101,10 @@ class SocketClient(Process):
|
||||||
return err
|
return err
|
||||||
print("Ready!")
|
print("Ready!")
|
||||||
while self.running:
|
while self.running:
|
||||||
self._gather_messages()
|
data = self._get_message()
|
||||||
while not self.inbox.empty():
|
if data is not None:
|
||||||
message, args = self.inbox.get()
|
self.outbox.put(self.handler(data))
|
||||||
self._send_message(message, *args)
|
self._process_inbox()
|
||||||
self.inbox.task_done()
|
|
||||||
self._gather_messages()
|
|
||||||
# response = input("> ")
|
|
||||||
# self._send_message(response)
|
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.running = False
|
self.running = False
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
|
from abots.net.socket_server_handler import SocketServerHandler
|
||||||
|
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
from select import select
|
from select import select
|
||||||
from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
|
from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
|
||||||
|
from multiprocessing import Process, Queue, JoinableQueue
|
||||||
|
|
||||||
class SocketServer(Thread):
|
class SocketServer(Process):
|
||||||
def __init__(self, host, port, listeners=5, buffer_size=4096,
|
def __init__(self, host, port, listeners=5, buffer_size=4096,
|
||||||
max_message_size=26214400, end_of_line="\r\n", handler=None):
|
max_message_size=26214400, end_of_line="\r\n", inbox=JoinableQueue(),
|
||||||
Thread.__init__(self)
|
outbox=Queue(), handler=None):
|
||||||
|
Process.__init__(self)
|
||||||
|
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
|
@ -14,7 +18,9 @@ class SocketServer(Thread):
|
||||||
self.buffer_size = buffer_size
|
self.buffer_size = buffer_size
|
||||||
self.max_message_size = max_message_size
|
self.max_message_size = max_message_size
|
||||||
self.end_of_line = end_of_line
|
self.end_of_line = end_of_line
|
||||||
self.handler = self._handler if handler is None else handler
|
self.inbox = inbox
|
||||||
|
self.outbox = outbox
|
||||||
|
self.handler = SocketServerHandler if handler is None else handler
|
||||||
self.sock = socket(AF_INET, SOCK_STREAM)
|
self.sock = socket(AF_INET, SOCK_STREAM)
|
||||||
self.sock_fd = -1
|
self.sock_fd = -1
|
||||||
self.lookup = list()
|
self.lookup = list()
|
||||||
|
@ -22,53 +28,9 @@ class SocketServer(Thread):
|
||||||
self.clients = dict()
|
self.clients = dict()
|
||||||
self.running = True
|
self.running = True
|
||||||
|
|
||||||
def _handler(self, sock, message):
|
|
||||||
print("RAW", message)
|
|
||||||
if message == "STOP":
|
|
||||||
self.broadcast(self.sock, "STOP")
|
|
||||||
self.stop()
|
|
||||||
return -1
|
|
||||||
if message == "QUIT":
|
|
||||||
client_fd = self.get_client_fd(sock)
|
|
||||||
if client_fd is None:
|
|
||||||
return 0
|
|
||||||
client_address = [a for fd, a in self.lookup if fd == client_fd][0]
|
|
||||||
client_name = "{}:{}".format(*client_address)
|
|
||||||
self.broadcast(self.sock, "LEAVE {}".format(client_name))
|
|
||||||
self._close_sock(sock)
|
|
||||||
return 1
|
|
||||||
elif message == "LIST":
|
|
||||||
fds = list() #list(map(str, self.clients.keys()))
|
|
||||||
client_fd = self.get_client_fd(sock)
|
|
||||||
for fd in self.clients.keys():
|
|
||||||
if fd == self.sock_fd:
|
|
||||||
fds.append("*{}".format(fd))
|
|
||||||
elif fd == client_fd:
|
|
||||||
fds.append("+{}".format(fd))
|
|
||||||
else:
|
|
||||||
fds.append(str(fd))
|
|
||||||
self.send(sock, ",".join(fds))
|
|
||||||
return 1
|
|
||||||
elif message[:5] == "SEND ":
|
|
||||||
params = message[5:].split(" ", 1)
|
|
||||||
if len(params) < 2:
|
|
||||||
return 0
|
|
||||||
fd, response = params
|
|
||||||
client_sock = self.clients.get(int(fd), dict()).get("sock", None)
|
|
||||||
if client_sock is None:
|
|
||||||
return 0
|
|
||||||
self.send(client_sock, response)
|
|
||||||
return 1
|
|
||||||
elif message[:6] == "BCAST ":
|
|
||||||
response = message[6:]
|
|
||||||
self.broadcast(sock, response)
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 2
|
|
||||||
|
|
||||||
def _close_sock(self, sock):
|
def _close_sock(self, sock):
|
||||||
self.sockets.remove(sock)
|
self.sockets.remove(sock)
|
||||||
fd = self.get_client_fd(sock)
|
fd = self._get_client_fd(sock)
|
||||||
if fd is not None:
|
if fd is not None:
|
||||||
del self.clients[fd]
|
del self.clients[fd]
|
||||||
sock.close()
|
sock.close()
|
||||||
|
@ -115,7 +77,7 @@ class SocketServer(Thread):
|
||||||
message_size = unpack(">I", raw_message_size)[0]
|
message_size = unpack(">I", raw_message_size)[0]
|
||||||
return message_size
|
return message_size
|
||||||
|
|
||||||
def get(self, sock):
|
def _get_message(self, sock):
|
||||||
message_size = self._get_message_size(sock)
|
message_size = self._get_message_size(sock)
|
||||||
if message_size is None:
|
if message_size is None:
|
||||||
return None
|
return None
|
||||||
|
@ -127,7 +89,7 @@ class SocketServer(Thread):
|
||||||
self._close_sock(sock)
|
self._close_sock(sock)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def send(self, sock, message, *args):
|
def _send_message(self, sock, message, *args):
|
||||||
packaged = self._package_message(message, *args)
|
packaged = self._package_message(message, *args)
|
||||||
try:
|
try:
|
||||||
sock.send(packaged)
|
sock.send(packaged)
|
||||||
|
@ -136,7 +98,14 @@ class SocketServer(Thread):
|
||||||
except OSError:
|
except OSError:
|
||||||
self._close_sock(sock)
|
self._close_sock(sock)
|
||||||
|
|
||||||
def get_client_fd(self, client_sock):
|
def _broadcast_message(self, client_sock, client_message, *args):
|
||||||
|
for sock in self.sockets:
|
||||||
|
not_server = sock != self.sock
|
||||||
|
not_client = sock != client_sock
|
||||||
|
if not_server and not_client:
|
||||||
|
self._send_message(sock, client_message, *args)
|
||||||
|
|
||||||
|
def _get_client_fd(self, client_sock):
|
||||||
try:
|
try:
|
||||||
return client_sock.fileno()
|
return client_sock.fileno()
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -146,12 +115,25 @@ class SocketServer(Thread):
|
||||||
return fd
|
return fd
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def broadcast(self, client_sock, client_message, *args):
|
def _process_inbox(self):
|
||||||
for sock in self.sockets:
|
while not self.inbox.empty():
|
||||||
not_server = sock != self.sock
|
data = self.inbox.get()
|
||||||
not_client = sock != client_sock
|
mode = data[0]
|
||||||
if not_server and not_client:
|
if mode == "SEND":
|
||||||
self.send(sock, client_message, *args)
|
client, message, args = data[1:]
|
||||||
|
self._send_message(message, *args)
|
||||||
|
elif mode == "BCAST":
|
||||||
|
message, args = data[1:]
|
||||||
|
self._broadcast_message(self.sock, message, *args)
|
||||||
|
self.inbox.task_done()
|
||||||
|
|
||||||
|
def _client_thread(self, sock):
|
||||||
|
while self.running:
|
||||||
|
message = self._get_message(sock)
|
||||||
|
if message is None:
|
||||||
|
continue
|
||||||
|
status = self.handler(self, sock, message)
|
||||||
|
self.outbox.put((status, message))
|
||||||
|
|
||||||
def _prepare(self):
|
def _prepare(self):
|
||||||
self.sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
|
self.sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
|
||||||
|
@ -171,44 +153,57 @@ class SocketServer(Thread):
|
||||||
self.clients[self.sock_fd]["sock"] = self.sock
|
self.clients[self.sock_fd]["sock"] = self.sock
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def start(self):
|
def send(self, client, message, *args):
|
||||||
|
self.inbox.put(("SEND", client, message, args))
|
||||||
|
|
||||||
|
def broadcast(self, message, *args):
|
||||||
|
self.inbox.put(("BCAST", message, args))
|
||||||
|
|
||||||
|
def results(self):
|
||||||
|
messages = list()
|
||||||
|
while not self.outbox.empty():
|
||||||
|
messages.append(self.outbox.get())
|
||||||
|
return messages
|
||||||
|
|
||||||
|
def run(self):
|
||||||
err = self._prepare()
|
err = self._prepare()
|
||||||
if err is not None:
|
if err is not None:
|
||||||
print(err)
|
print(err)
|
||||||
return err
|
return err
|
||||||
print("Server ready!")
|
print("Server ready!")
|
||||||
while self.running:
|
while self.running:
|
||||||
|
# try:
|
||||||
|
# selection = select(self.sockets, list(), list(), 5)
|
||||||
|
# read_socks, write_socks, err_socks = selection
|
||||||
|
# except OSError as e:
|
||||||
|
# print("Error", e)
|
||||||
|
# continue
|
||||||
|
# for sock in read_socks:
|
||||||
|
# if sock == self.sock:
|
||||||
try:
|
try:
|
||||||
selection = select(self.sockets, list(), list(), 5)
|
client_sock, client_address = self.sock.accept()
|
||||||
read_socks, write_socks, err_socks = selection
|
client_sock.settimeout(60)
|
||||||
except OSError as e:
|
except OSError:
|
||||||
print("Error", e)
|
|
||||||
continue
|
continue
|
||||||
for sock in read_socks:
|
client_name = "{}:{}".format(*client_address)
|
||||||
if sock == self.sock:
|
client_host, client_port = client_address
|
||||||
try:
|
client_fd = client_sock.fileno()
|
||||||
client_sock, client_address = self.sock.accept()
|
self.lookup.append((client_fd, client_sock))
|
||||||
client_sock.settimeout(60)
|
self.sockets.append(client_sock)
|
||||||
except OSError:
|
self.clients[client_fd] = dict()
|
||||||
continue
|
self.clients[client_fd]["host"] = client_host
|
||||||
client_name = "{}:{}".format(*client_address)
|
self.clients[client_fd]["port"] = client_port
|
||||||
client_host, client_port = client_address
|
self.clients[client_fd]["sock"] = client_sock
|
||||||
client_fd = client_sock.fileno()
|
joined = "ENTER {}".format(client_name)
|
||||||
self.lookup.append((client_fd, client_sock))
|
self.outbox.put((1, joined))
|
||||||
self.sockets.append(client_sock)
|
self._broadcast_message(client_sock, joined)
|
||||||
self.clients[client_fd] = dict()
|
Thread(target=self._client_thread, args=(client_sock,)).start()
|
||||||
self.clients[client_fd]["host"] = client_host
|
# else:
|
||||||
self.clients[client_fd]["port"] = client_port
|
# message = self._get_message(sock)
|
||||||
self.clients[client_fd]["sock"] = client_sock
|
# if message is None:
|
||||||
joined = "ENTER {}".format(client_name)
|
# continue
|
||||||
print(joined)
|
# status = self.handler(self, sock, message)
|
||||||
self.broadcast(client_sock, joined)
|
# self.outbox.put((status, message))
|
||||||
else:
|
|
||||||
message = self.get(sock)
|
|
||||||
if message is None:
|
|
||||||
continue
|
|
||||||
status = self.handler(sock, message)
|
|
||||||
print(status, message)
|
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.running = False
|
self.running = False
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
def SocketServerHandler(server, sock, message):
|
||||||
|
print("RAW:", message)
|
||||||
|
if message == "STOP":
|
||||||
|
server._broadcast_message(server.sock, "STOP")
|
||||||
|
server.stop()
|
||||||
|
return -1
|
||||||
|
if message == "QUIT":
|
||||||
|
client_fd = server._get_client_fd(sock)
|
||||||
|
if client_fd is None:
|
||||||
|
return 0
|
||||||
|
client_address = [a for fd, a in server.lookup if fd == client_fd][0]
|
||||||
|
client_name = "{}:{}".format(*client_address)
|
||||||
|
server._broadcast_message(server.sock, "LEAVE {}".format(client_name))
|
||||||
|
server._close_sock(sock)
|
||||||
|
return 1
|
||||||
|
elif message == "LIST":
|
||||||
|
fds = list() #list(map(str, server.clients.keys()))
|
||||||
|
client_fd = server._get_client_fd(sock)
|
||||||
|
for fd in server.clients.keys():
|
||||||
|
if fd == server.sock_fd:
|
||||||
|
fds.append("*{}".format(fd))
|
||||||
|
elif fd == client_fd:
|
||||||
|
fds.append("+{}".format(fd))
|
||||||
|
else:
|
||||||
|
fds.append(str(fd))
|
||||||
|
server._send_message(sock, ",".join(fds))
|
||||||
|
return 1
|
||||||
|
elif message[:5] == "SEND ":
|
||||||
|
params = message[5:].split(" ", 1)
|
||||||
|
if len(params) < 2:
|
||||||
|
return 0
|
||||||
|
fd, response = params
|
||||||
|
client_sock = server.clients.get(int(fd), dict()).get("sock", None)
|
||||||
|
if client_sock is None:
|
||||||
|
return 0
|
||||||
|
server._send_message(client_sock, response)
|
||||||
|
return 1
|
||||||
|
elif message[:6] == "BCAST ":
|
||||||
|
response = message[6:]
|
||||||
|
server._broadcast_message(sock, response)
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 2
|
|
@ -4,10 +4,10 @@ import sys
|
||||||
sys.path.insert(0, "/center/lib")
|
sys.path.insert(0, "/center/lib")
|
||||||
|
|
||||||
from abots.net import SocketClient
|
from abots.net import SocketClient
|
||||||
from multiprocessing import JoinableQueue, Queue
|
|
||||||
|
|
||||||
inbox = JoinableQueue()
|
host = "127.0.0.1"
|
||||||
outbox = Queue()
|
port = 10701
|
||||||
client = SocketClient("127.0.0.1", 10701, inbox=inbox, outbox=outbox)
|
|
||||||
client.send("LIST")
|
client = SocketClient(host, port)
|
||||||
|
client.daemon = True
|
||||||
client.start()
|
client.start()
|
|
@ -3,18 +3,11 @@
|
||||||
import sys
|
import sys
|
||||||
sys.path.insert(0, "/center/lib")
|
sys.path.insert(0, "/center/lib")
|
||||||
|
|
||||||
from abots.net import SocketServer, SocketClient
|
from abots.net import SocketServer
|
||||||
from multiprocessing import Process
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
host = "127.0.0.1"
|
host = "127.0.0.1"
|
||||||
port = 10701
|
port = 10701
|
||||||
|
|
||||||
server = SocketServer(host, port)
|
server = SocketServer(host, port)
|
||||||
server.start()
|
server.daemon = True
|
||||||
# pserver = Process(target=lambda x: x.start(), args=(server,))
|
server.start()
|
||||||
# pserver.start()
|
|
||||||
# sleep(1)
|
|
||||||
# if type(input("Start client: ")) is str:
|
|
||||||
# client = SocketClient(host, port)
|
|
||||||
# client.start()
|
|
Loading…
Reference in New Issue