https://github.com/lbxa/ghostr
CLI socket chat app
https://github.com/lbxa/ghostr
p2p python server
Last synced: 9 months ago
JSON representation
CLI socket chat app
- Host: GitHub
- URL: https://github.com/lbxa/ghostr
- Owner: lbxa
- Created: 2021-11-11T06:34:25.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2021-11-19T04:28:00.000Z (over 4 years ago)
- Last Synced: 2025-04-18T22:43:09.227Z (about 1 year ago)
- Topics: p2p, python, server
- Language: Python
- Homepage:
- Size: 73.2 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Assignment Report
Lucas Barbosa (z5259433) COMP3331 21T3
# 1. Installation
## 1.1. Pyenv
Using Python version 3.7.0 (installed locally with pyenv) and managed using venv.
```
$ pyenv install 3.7.0
$ pyenv local 3.7.0
$ python -m venv .venv
$ . .venv/bin/activate
(.venv) $ ...
```
For VSCode venv configuration add these lines to the `.vscode/settings.json` file
```json
"python.terminal.activateEnvironment": true
```
## 1.2. Regular Python
The version of Python used for this project was `3.7.0`.
## 1.3. Usage
On CSE machines:
- Server
```
python3 server.py 3331 10 120
```
- Client
```
python3 client.py 3331
```
NOTE*: For private messages both users must use `privatestart ` to initiate a private chat
# 2. Design Choices
## 2.1. Software
- Originally I designed an overcomplicated messaging protocol (XMPP) which made parsing messages between server and client more error prone.
- A simple fix was to switch JSON format. The obvious advantages its lightweightness, user-friendlyness and wide adoption.
- Python was the choice of programming language because of its simplicity, especially for socket programming. Java and C would result in many more lines of code. The **tradeoff** was type and memory safety in exchange for a faster production time. This was a crucial factor considering the numerous deadlines in the final weeks of the term.
- Multi-threading was used heavily throughout both the client, server and P2P programs. Threads brought more flexibilty and control instead of using the `select` module.
- Threads are easily inheritered by custom classes which carry all the functionality to make sending and receiving data asynchronously effortless.
- Killing threads was very easy and made the program more stable in the case of an unexpected socket failure.
- Design patterns such as lookup tables were used to elliminate giant if/else blocks where possible (evident in client.py)
## 2.1. Data Structures
- Python sets were used where a data structure that ensured no duplicate items was needed.
- Classes were used to encapsulate multiple functions that belonged to the same domain of functionality (e.g. User class in `user.py`)
- Codebase was split into multiple files (Python modules) for organisation based on functionality
- [server.py](http://server.py) handles all the server functionality
- [client.py](http://client.py) handles all client functionality including P2P connections
- [user.py](http://user.py) contains all management and CRUD operations for individual user operations
- [admin.py](http://admin.py) contains all functions responsible for managing all users and their P2P connections
- [library.py](http://library.py) contains any helper or auxiliary methods
- [constants.py](http://constants.py) holds all constant values common to all modules
# 3. Protocol
For this assignment, I am adapting my own messaging protocol which is inspired by the [XMPP protocol](https://en.wikipedia.org/wiki/XMPP) used by WhatsApp.
Eventually it became way too overkill and I integrated it with JSON to simplify the program logic. Having a more complex protocol layer also made the server more prone to message parsing and encoding errors.
## 3.1. Logging On
```
# Request
TYPE: LOGON;;
WHO: ;;
# Response
TYPE: LOGON;;
RET: <1|0>;;
NEW: <1|0>;;
ERR: <0|string>;;
```
### 3.1.1. Logged In
The server will notify the client when a user has successfully logged in
```
# Response
TYPE: LOGGEDIN;;
WHO: ;;
```
## 3.2. Auth
```
# Request
TYPE: AUTH;;
WHO: ;;
PASW: ;;
NEW: <1|0>;;
# Response
TYPE: AUTH;;
PASW: <1|0>;;
ATMP: ;;
```
```json
{
"action": "login",
"username": "username",
"password": "password",
"private_port": "private_recv_port"
}
```
| action | Description of action the server is taking next. |
| --- | --- |
| username | String |
| password | String |
| private_port | Each user is assigned a private port upon authentication. This enables the P2P connection for private messaging. |
## 3.3. Messaging
For a unicast message (send and received by one person):
```
TYPE: MSG;;
FROM: ;;
TO: ;;
BODY: ;;
```
For a broadcasted message (sent by one and receivd by many):
```
TYPE: BROADCAST;;
FROM: ;;
BODY: ;;
```
```json
{
"action": "message",
"message": "message_contents",
"user": "username"
}
```
## 3.4. Auxilliary Commands
### 3.4.1. Whoelse
```
# Request
TYPE: WHOELSE;;
FROM: ;;
# Response
TYPE: WHOELSE;;
FROM: ;;
BODY: ;;
```
| TYPE | Command signature |
| --- | --- |
| FROM | The user who issued the command |
| BODY | Comma-separated list of names of users that are currently online |
### 3.4.2. Whoelsesince
```
# Request
TYPE: WHOELSESINCE;;
WHEN:
# Response
TYPE: WHOELSESINCE;;
WHEN:
| TYPE | Command signature |
| --- | --- |
| WHEN | Time to check since users were last active |
| FROM | The user who issued the command |
| BODY | Comma-separated list of names of users that are currently online since TIME x in seconds |
## 3.5. Blocking
Blocks user with a `username` for an indefinite period of time.
```
# Request
TYPE: BLOCK|UNBLOCK;;
WHO: ;;
BLOCKER: ;;
# Response
TYPE: BLOCK|UNBLOCK;;
WHO: ;;
BLOCKER: ;;
RET: <1|0>;;
ERR: <0|string>;;
```
### 3.5.1. Server Blocking
If a user is blocked by the server from multiple incorrect password attempts the field in the blocked data structure would look like this:
```json
{
"username": "string",
"start": "string",
"end": "string",
"blocked_by": "!SERVER!"
}
```
| START | Time when server blocked user. |
| --- | --- |
| END | Timestamp for when server blocking expires. |
| BLOCKED_BY | Differentiates between regular use and daemon process. |
### 3.5.2. User Blocking
If a user blocks another user manually it will look slightly differently:
```json
{
"username": "string",
"start": "",
"end": "",
"blocked_by": "string"
}
```
| START | Not required. |
| --- | --- |
| END | Not required. |
| BLOCKED_BY | Regular user who has blocked username |
When a user is blocked/unblocked by another user the JSON message follows this structure:
```json
{
"action": "block/unblock",
"user": "username",
}
```
## 3.6. Private
### 3.6.1. Start Private
```
# Request
TYPE: PRIVREQ;;
TO: ;;
FROM: ;;
# Response
TYPE: PRIVREQ;;
TO: ;;
FROM: ;;
RET: <0|1>;;
DEST: ;;
```
| TO | User on the other side of the private message request. |
| --- | --- |
| RET | Flag to verify whether user has accepted the invitation to a private chat. |
| DEST | Port destination for the current client to communicate with in order to bypass the server. |
### 3.6.2. Private Messages
```
# Request
TYPE: PRIVMSG;;
TO: ;;
FROM: ;;
BODY: ;;
# Response
TYPE: PRIVMSG;;
TO: ;;
FROM: ;;
BODY: ;;
```
### 3.6.3. Stop Private
```
# Request
TYPE: PRIVSTOP;;
TO: ;;
FROM: ;;
# Response
TYPE: PRIVSTOP;;
TO: ;;
FROM: ;;
RET: <0|1>;;
```
## 3.7 Logout
```
# Request
TYPE: LOGOUT;;
WHO: ;;
# Response
TYPE: LOGOUT;;
WHO: ;;
# Response
TYPE: LOGGEDOUT;;
WHO: ;;
```
# 4. Improvements
- Add a type-checking system for Python to ensure maximal type safety (such as mypy)
- More error checking for incorrect command syntax from the user
- Adding a `--help` option that lists all available commands and how to use them
- Support for file upload and download
- Support for communicating beyond a single machine (hosting on a web server)
# 5. Acknowledgments
- COMP3331 21T3 provided [TCPClient.py](http://TCPClient.py) and [TCPServer.py](http://TCPServer.py) multi-threaded examples
- Rui Li's explanation of P2P during Week 10 Lab
- Salil's COMP331 Lecture material on TCP connections and socket programming
- Various Youtube tutorials on Python socket programming and multi-threading
- [Stackoverflow.com](http://Stackoverflow.com) for Pythonic design principles and syntactical sugar
- Example of how to print to the terminal safely when asynchronously receiving messages from the server that will also be displayed on the terminal
```python
import readline
def chat_print(*args):
sys.stdout.write("\r" + " " * (len(readline.get_line_buffer()) + 2) + "\r")
print(*args)
sys.stdout.write("# " + readline.get_line_buffer())
sys.stdout.flush()
```