Skip to content

Commit

Permalink
added client base
Browse files Browse the repository at this point in the history
  • Loading branch information
Arterialist committed May 25, 2018
1 parent ca26f71 commit 2592557
Show file tree
Hide file tree
Showing 13 changed files with 486 additions and 0 deletions.
104 changes: 104 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
Empty file added client/__init__.py
Empty file.
209 changes: 209 additions & 0 deletions client/client_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import socket
import threading
from json import JSONDecodeError

from client import layers
from client.models.packets import Packet
from client.modules.default_modules import SendAsJSONModule

# load modules
loaded_modules = [SendAsJSONModule()]

nickname = None
local_port = None

sock = None
server_host = None
server_port = None

connected = False
listening = False

has_incoming_connection = False
incoming_connection = None
incoming_connection_address = None

current_connection = None
current_connection_address = None
current_peer_id = None

incoming_message_thread = None
incoming_connection_thread = None
message_sending_thread = None

incoming_connection_callback = None
new_message_callback = None


def init_socket():
global sock, connected
connected = False
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)


def incoming_connections_listener():
global has_incoming_connection, incoming_connection, incoming_connection_address
while 1:
try:
connection, address = sock.accept()
incoming_connection = connection
incoming_connection_address = address
has_incoming_connection = True
if incoming_connection_callback:
incoming_connection_callback()
except OSError:
continue


def p2p_new_message_listener():
global current_connection, connected
while connected:
data = current_connection.recv(4096)
if data == b'':
print('Connection closed')
connected = False
break
try:
recv_msg = Packet.from_json_obj(layers.socket_handle_received(current_connection, data.decode('utf8'), loaded_modules))
recv_msg.message.mine = False
if new_message_callback:
new_message_callback(recv_msg)
print(recv_msg.__dict__)
except UnicodeDecodeError:
print('Corrupted message')
except JSONDecodeError:
print('Received non-JSON message (raw connection?)')
except KeyError:
print("Invalid JSON schema")


def server_new_message_listener():
global current_connection
while connected:
data = current_connection.recv(4096)
try:
if new_message_callback:
new_message_callback('\n' + data.decode('utf8'))
print('\n' + data.decode('utf8'))
except UnicodeDecodeError:
print('Corrupted message')


def socket_listen_off():
global listening
sock.close()
if incoming_connection_thread:
incoming_connection_thread.join(0)
init_socket()
listening = False


def socket_listen_on():
global sock, incoming_connection_thread, listening
socket_listen_off()

try:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', local_port))
except socket.error as e:
print('Bind failed.')
print(e)
return

sock.listen(256)

incoming_connection_thread = threading.Thread(target=incoming_connections_listener)
incoming_connection_thread.setDaemon(True)
incoming_connection_thread.start()
listening = True


def p2p_connect(remote_host, remote_port):
global current_connection, current_connection_address, incoming_message_thread, connected
socket_listen_off()

current_connection_address = (remote_host, remote_port)
current_connection = sock
try:
sock.connect(current_connection_address)
except ConnectionRefusedError:
print('Client is offline')
return

connected = True
incoming_message_thread = threading.Thread(target=p2p_new_message_listener)
incoming_message_thread.setDaemon(True)
incoming_message_thread.start()
print('Connected to client')


def server_connect():
global current_connection_address, current_connection, incoming_message_thread, connected
socket_listen_off()

current_connection_address = (server_host, server_port)
current_connection = sock
sock.connect(current_connection_address)

connected = True
incoming_message_thread = threading.Thread(target=server_new_message_listener)
incoming_message_thread.setDaemon(True)
incoming_message_thread.start()
print('Connected to server')


def accept_connection():
global current_connection, current_connection_address, connected, incoming_message_thread
current_connection = incoming_connection
current_connection_address = incoming_connection_address
connected = True
incoming_message_thread = threading.Thread(target=p2p_new_message_listener)
incoming_message_thread.setDaemon(True)
incoming_message_thread.start()


def decline_connection():
global incoming_connection, incoming_connection_address
incoming_connection.close()
incoming_connection = None
incoming_connection_address = None


def send_message(message):
# pass your modules here
layers.socket_send_data(current_connection, message, loaded_modules)


def disconnect():
global current_connection, incoming_message_thread, incoming_connection_thread, connected, current_peer_id
connected = False

current_peer_id = None

if current_connection:
current_connection.detach()
current_connection.close()

if incoming_message_thread:
incoming_message_thread.join(0)
if incoming_connection_thread:
incoming_connection_thread.join(0)


def finish():
global sock, current_connection, incoming_message_thread, incoming_connection_thread, connected

connected = False
sock.detach()
sock.close()

if current_connection:
current_connection.detach()
current_connection.close()

if incoming_message_thread:
incoming_message_thread.join(0)
if incoming_connection_thread:
incoming_connection_thread.join(0)

exit(0)
18 changes: 18 additions & 0 deletions client/layers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""
this file is created to make functionality growth fast
"""


def socket_send_data(to, what, through=list()):
for action in through:
what = action.process(what)

if to:
to.sendall(what)


def socket_handle_received(from_s, what, through=list()):
for action in through:
what = action.process_s(what, from_s)

return what
Empty file added client/models/__init__.py
Empty file.
31 changes: 31 additions & 0 deletions client/models/actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from client.models.base import Jsonable


class Action(Jsonable):
def __init__(self, action="new"):
self.action = action


class NewMessageAction(Action):
def __init__(self):
super().__init__(action="new")


class EditMessageAction(Action):
def __init__(self):
super().__init__(action="edit")


class ReplyMessageAction(Action):
def __init__(self):
super().__init__(action="reply")


class ForwardMessageAction(Action):
def __init__(self):
super().__init__(action="forward")


class DeleteMessageAction(Action):
def __init__(self):
super().__init__(action="delete")
18 changes: 18 additions & 0 deletions client/models/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import json


class Jsonable:
@staticmethod
def from_json(json_string):
obj = Jsonable()
obj.__dict__ = json.loads(json_string)
return obj

@staticmethod
def from_json_obj(json_obj):
obj = Jsonable()
obj.__dict__ = json_obj
return obj

def to_json(self):
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True)
Loading

0 comments on commit 2592557

Please sign in to comment.