Skip to content

Commit

Permalink
added docs generation and reformatted code
Browse files Browse the repository at this point in the history
  • Loading branch information
Floskinner committed May 19, 2023
1 parent 5179e97 commit c6217b4
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 41 deletions.
45 changes: 45 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: website

# build the documentation whenever there are new commits on main
on:
push:
branches:
- main

# security: restrict permissions for CI jobs.
permissions:
contents: read

jobs:
# Build the documentation and upload the static HTML files as an artifact.
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.9'
- uses: abatilo/actions-poetry@v2

# ADJUST THIS: install all dependencies (including pdoc)
- run: pip install -r requirements.txt
- run: pip install pdoc
# ADJUST THIS: build your documentation into docs/.
# We use a custom build script for pdoc itself, ideally you just run `pdoc -o docs/ ...` here.
- run: pdoc -o ./docs/ src/client.py src/server.py src/services.py src/transport_message.py

- uses: actions/upload-pages-artifact@v1
with:
path: docs/

# Deploy the artifact to GitHub pages.
# This is a separate job so that only actions/deploy-pages has the necessary permissions.
deploy:
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
steps:
- id: deployment
uses: actions/deploy-pages@v2
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,6 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# Ignore docs
docs/
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Florian Glaser, Florian Herkommer, David Felder, Miriam Astor, Steffen Freitag
Server starten:

```bash
python server.py
python src/server.py

>>> ======== Running on http://127.0.0.1:8080 ========
>>> (Press CTRL+C to quit)
Expand All @@ -16,13 +16,13 @@ python server.py
- Ein Topic subscriben:

```bash
python client.py --server http://127.0.0.1:8080 --subscribe first_topic second_topic
python src/client.py --server http://127.0.0.1:8080 --subscribe first_topic second_topic
```

- Eine Nachricht für Topics schreiben:

```bash
python client.py --server http://127.0.0.1:8080 --publish second_topic --message "Hello World Message"
python src/client.py --server http://127.0.0.1:8080 --publish second_topic --message "Hello World Message"
```

- ...
Expand Down
Empty file removed src/__init__.py
Empty file.
14 changes: 10 additions & 4 deletions src/client.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import atexit
import socketio
"""Starts a Client to communicate with the server. For more information, please run `python client.py --help`"""

import argparse
import time
import atexit
import json
import sys, os
import os
import sys
import time
from contextlib import redirect_stderr

import socketio

from transport_message import TransportMessage


class Client:
"""
Client object for publisher server
Expand Down
84 changes: 51 additions & 33 deletions src/server.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import socketio
"""Server for publisher subscriber system. For more information, please run `python server.py --help`"""

import asyncio
import json
import time
import asyncio
from datetime import datetime
from aiohttp import web
from argparse import ArgumentParser
from typing import List
from transport_message import TransportMessage
from datetime import datetime
from threading import Thread
from typing import List

import socketio
from aiohttp import web

from transport_message import TransportMessage

parser = ArgumentParser(prog="server.py", description="Starts a server for publisher subscriber system")
parser.add_argument("-p", "--port", type=str, help="Port to run the server on. Default is 8080", default=8080, metavar="PORT")
parser.add_argument("--host", type=str, help="Host to run the server on. Default is localhost", default="127.0.0.1", metavar="HOST")
parser.add_argument(
"-p", "--port", type=str, help="Port to run the server on. Default is 8080", default=8080, metavar="PORT"
)
parser.add_argument(
"--host", type=str, help="Host to run the server on. Default is localhost", default="127.0.0.1", metavar="HOST"
)


class ParallelTimer(Thread):
Expand All @@ -27,12 +34,18 @@ def run(self):


class Topic:
def __init__(self) -> None:
self.name = None
self.content = None
self.subscribers: List[str] = []
self.timestamp = None
self.last_update = None
"""Class to manage the Topics with needed data."""

name = None
"""name of the topic"""
content = None
"""content of the topic"""
subscribers: List[str] = []
"""list of subscribers"""
timestamp = None
"""timestamp"""
last_update = None
"""last update of topic"""


class Server:
Expand All @@ -47,12 +60,10 @@ def __init__(self, args) -> None:
self.sio.on("LIST_TOPICS", self.handle_list_topics)
self.sio.on("GET_TOPIC_STATUS", self.handle_topic_status)


async def connect(self, sid, environ, auth):
print(f"{sid} connected ({environ['REMOTE_ADDR']})")


async def handle_subscribe(self, sid, data = None) -> None:
async def handle_subscribe(self, sid, data=None) -> None:
# Check if data is None
if data is None:
response = TransportMessage(timestamp=int(time.time()), payload="Internal Server Error.")
Expand All @@ -69,24 +80,29 @@ async def handle_subscribe(self, sid, data = None) -> None:
if topic.name == data["topic"]:
# Check if sid already subscribed to topic
if sid in topic.subscribers:
response = TransportMessage(timestamp=int(time.time()), payload=f"Already subscribed to {data['topic']}.")
response = TransportMessage(
timestamp=int(time.time()), payload=f"Already subscribed to {data['topic']}."
)
await self.sio.emit("PRINT_MESSAGE", response.json(), room=sid)
return None
# Subscribe to topic
topic.subscribers.append(sid)
response = TransportMessage(timestamp=int(time.time()), payload=f"Successfully subscribed to {data['topic']}.")
response = TransportMessage(
timestamp=int(time.time()), payload=f"Successfully subscribed to {data['topic']}."
)
await self.sio.emit("PRINT_MESSAGE", response.json(), room=sid)
return None
# Create new topic if not already existing and subscribe
new_topic = Topic()
new_topic.name = data["topic"]
new_topic.subscribers.append(sid)
self.list_of_topics.append(new_topic)
response = TransportMessage(timestamp=int(time.time()), payload=f"Created {data['topic']} and successfully subscribed.")
response = TransportMessage(
timestamp=int(time.time()), payload=f"Created {data['topic']} and successfully subscribed."
)
await self.sio.emit("PRINT_MESSAGE", response.json(), room=sid)


async def handle_unsubscribe(self, sid, data = None) -> None:
async def handle_unsubscribe(self, sid, data=None) -> None:
# Check if data is None
if data is None:
response = TransportMessage(timestamp=int(time.time()), payload="Internal Server Error.")
Expand All @@ -104,7 +120,9 @@ async def handle_unsubscribe(self, sid, data = None) -> None:
# Check if sid subscribed to topic and unsubscribe
if sid in topic.subscribers:
topic.subscribers.remove(sid)
response = TransportMessage(timestamp=int(time.time()), payload=f"Successfully unsubscribed from {data['topic']}.")
response = TransportMessage(
timestamp=int(time.time()), payload=f"Successfully unsubscribed from {data['topic']}."
)
await self.sio.emit("PRINT_MESSAGE_AND_EXIT", response.json(), room=sid)
return None
# Not subscribed
Expand All @@ -115,8 +133,7 @@ async def handle_unsubscribe(self, sid, data = None) -> None:
response = TransportMessage(timestamp=int(time.time()), payload=f"{data['topic']} does not exist.")
await self.sio.emit("PRINT_MESSAGE_AND_EXIT", response.json(), room=sid)


async def handle_publish(self, sid, data = None) -> None:
async def handle_publish(self, sid, data=None) -> None:
# Check if data is None
if data is None:
response = TransportMessage(timestamp=int(time.time()), payload="Internal Server Error.")
Expand All @@ -138,24 +155,24 @@ async def handle_publish(self, sid, data = None) -> None:
if topic.name == data["topic"]:
topic.content = data["payload"]
topic.timestamp = data["timestamp"]
response = TransportMessage(timestamp=int(time.time()), payload=f"Successfully published message to {data['topic']}.")
response = TransportMessage(
timestamp=int(time.time()), payload=f"Successfully published message to {data['topic']}."
)
await self.sio.emit("PRINT_MESSAGE_AND_EXIT", response.json(), room=sid)
await self.update_topic(data["topic"])
return None
# Topic not existing
response = TransportMessage(timestamp=int(time.time()), payload=f"{data['topic']} does not exist.")
await self.sio.emit("PRINT_MESSAGE_AND_EXIT", response.json(), room=sid)


async def handle_list_topics(self, sid, data = None) -> None:
async def handle_list_topics(self, sid, data=None) -> None:
response_msg = "All topics on the server:"
for topic in self.list_of_topics:
response_msg += f"\n{topic.name}"
response = TransportMessage(timestamp=int(time.time()), payload=response_msg)
await self.sio.emit("PRINT_MESSAGE_AND_EXIT", response.json(), room=sid)


async def handle_topic_status(self, sid, data = None) -> None:
async def handle_topic_status(self, sid, data=None) -> None:
# Check if data is None
if data is None:
response = TransportMessage(timestamp=int(time.time()), payload="Internal Server Error.")
Expand Down Expand Up @@ -184,18 +201,19 @@ async def handle_topic_status(self, sid, data = None) -> None:
response = TransportMessage(timestamp=int(time.time()), payload=f"{data['topic']} does not exist.")
await self.sio.emit("PRINT_MESSAGE_AND_EXIT", response.json(), room=sid)


async def update_topic(self, topic) -> None:
for t in self.list_of_topics:
if t.name == topic:
t.last_update = int(time.time())
response = TransportMessage(timestamp=int(time.time()), payload=f"{t.name} ({datetime.fromtimestamp(int(t.timestamp)).strftime('%d-%m-%Y %H:%M:%S')}): {t.content}")
response = TransportMessage(
timestamp=int(time.time()),
payload=f"{t.name} ({datetime.fromtimestamp(int(t.timestamp)).strftime('%d-%m-%Y %H:%M:%S')}): {t.content}",
)
# Top1 (17.05.2023, 09:12): Content hier
for sub in t.subscribers:
await self.sio.emit("PRINT_MESSAGE", response.json(), room=sub)
print("sent")


async def heart_beat(self, time_delta):
for topic in self.list_of_topics:
if topic.last_update is not None and int(time.time()) - topic.last_update > time_delta:
Expand Down
2 changes: 2 additions & 0 deletions src/services.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Contain the services that the server can provide to the client."""
from enum import Enum


class Services(Enum):
SUBSCRIBE_TOPIC = 0
UNSUBSCRIBE_TOPIC = 1
Expand Down
2 changes: 1 addition & 1 deletion src/transport_message.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from pydantic import BaseModel
from typing import Optional


class TransportMessage(BaseModel):
timestamp: int
topic: Optional[str]
payload: Optional[str]

0 comments on commit c6217b4

Please sign in to comment.