Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
./old_bot
.idea/
__pycache__
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./application /code/application
COPY ./main.py /code/

ENTRYPOINT ["python", "/code/main.py"]
ENTRYPOINT ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "5000"]
45 changes: 34 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,44 @@
## Client-Server-Kommunikation

- der Client verbindet sich mit dem Server per websocket
- zu Beginn sendet der client seine Platform und version als json zum server:
```json
{"platform":"python", "version":999}
```
- sobald der client in 0 Lage ist ein pixel zu setzen schickt dieser ein `request_pixel` an den server
- der Server antwortet dann mit dem zu setzenden pixel als json, e.g.:
- Der Client verbindet sich mit dem Server per websocket
- Zu Beginn sendet der client seine Platform und version als json zum server:
```json
{
"operation":"pixel",
"data":{
"operation": "handshake",
"data": {
"platform": "python",
"version": 999
}
}
```

- Sollte der Server feststellen, dass der Client eine alte Version verwendet, sendet er diesem eine Update aufforderung zurück:
```json
{
"operation": "notify-update"
}
```

- sobald der client in 0 Lage ist ein pixel zu setzen schickt dieser ein `request-pixel` an den server
```json
{
"operation": "request-pixel",
"user": "<user-id">"
}
```

- der Server antwortet dann mit dem zu setzenden pixel als json, e.g.:
```json
{
"operation": "place-pixel",
"data": {
"x": 0,
"y": 857,
"color": 4,
"priority": 1
}
},
"user": "<user-id">"
}
```
- wenn kein Pixel existiert, wird `null` zurückgesendet.

- wenn kein Pixel existiert, wird `{}` zurückgesendet.
File renamed without changes.
32 changes: 32 additions & 0 deletions application/api/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from application.api.config import ServerConfig
from application.canvas.canvas import Canvas
from application.color import get_color_from_index


async def request_pixel(canvas: Canvas):
pixel = await canvas.pop_mismatched_pixel()
if pixel:
return {
'x': pixel['x'],
'y': pixel['y'],
'color': get_color_from_index(pixel['color_index']).value['id']
}
else:
return {}


# no-op
async def handshake():
pass


def ping():
return {
'pong': True
}


def version_check(settings: ServerConfig, data: dict):
client_version = data.get('version', -1)
# wenn der client nix schickt nehmen wir an, dass er in ordnung ist
return client_version < 0 or client_version >= settings.min_version
27 changes: 27 additions & 0 deletions application/api/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from pydantic import BaseSettings


class ServerConfig(BaseSettings):
remote_config_url: str = 'https://placede.github.io/pixel/pixel.json'
canvas_update_interval: int = 10
min_version: int = 0


def get_graphql_config():
return {
"id": "1",
"type": "start",
"payload": {
"variables": {
"input": {
"channel": {
"teamOwner": "AFD2022",
"category": "CONFIG",
}
}
},
"extensions": {},
"operationName": "configuration",
"query": "subscription configuration($input: SubscribeInput!) {\n subscribe(input: $input) {\n id\n ... on BasicMessage {\n data {\n __typename\n ... on ConfigurationMessageData {\n colorPalette {\n colors {\n hex\n index\n __typename\n }\n __typename\n }\n canvasConfigurations {\n index\n dx\n dy\n __typename\n }\n canvasWidth\n canvasHeight\n __typename\n }\n }\n __typename\n }\n __typename\n }\n}\n",
},
}
33 changes: 33 additions & 0 deletions application/api/connection_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from typing import List

from fastapi import WebSocket


class ConnectionManager:
def __init__(self):
self.active_connections: List[WebSocket] = []
self.advertised_accounts: dict = {}

async def connect(self, websocket: WebSocket):
await websocket.accept()
self.active_connections.append(websocket)

def set_advertised_accounts(self, websocket: WebSocket, count):
self.advertised_accounts[websocket] = count

def disconnect(self, websocket: WebSocket):
self.active_connections.remove(websocket)
self.advertised_accounts.pop(websocket)

async def send_message_to(self, message: str, websocket: WebSocket):
await websocket.send_text(message)

async def broadcast(self, message: str):
for connection in self.active_connections:
await connection.send_text(message)

def connection_count(self):
return len(self.active_connections)

def advertised_account_count(self):
return sum(self.advertised_accounts.values())
3 changes: 1 addition & 2 deletions application/canvas/canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from PIL import Image

from application.color import get_matching_color, Color, get_color_from_index
from application.static_stuff import CANVAS_UPDATE_INTERVAL
from application.target_configuration.target_configuration import TargetConfiguration

BOARD_SIZE_X = 2000
Expand Down Expand Up @@ -95,7 +94,7 @@ async def update_board(self):
"""
Fetch the current state of the board/canvas for the requed areas
"""
if self.last_update + CANVAS_UPDATE_INTERVAL >= time.time():
if self.last_update + self.target_configuration.settings.canvas_update_interval >= time.time():
return False
await self.update_access_token()

Expand Down
99 changes: 0 additions & 99 deletions application/connections/websocket_server.py

This file was deleted.

Empty file removed application/frontend/__init__.py
Empty file.
8 changes: 0 additions & 8 deletions application/frontend/frontend.py

This file was deleted.

21 changes: 0 additions & 21 deletions application/static_stuff.py

This file was deleted.

14 changes: 7 additions & 7 deletions application/target_configuration/target_configuration.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import json
import random
import time
import asyncio

import aiohttp
import requests

from application import static_stuff
from application.api.config import ServerConfig

UPDATE_INTERVAL = 60

Expand All @@ -17,16 +15,18 @@ class TargetConfiguration:
Is refreshed periodically by pulling it from a server
"""

def __init__(self):
def __init__(self, settings: ServerConfig):
self.last_update = 0
self.config = {}
self.pixels = []
self.settings = settings
print(settings)

async def get_config(self, ignore_time: bool = False):
"""
Get the config and refresh it first if necessary
"""
if self.last_update + UPDATE_INTERVAL < time.time() and not ignore_time:
if self.last_update + self.settings.canvas_update_interval < time.time() and not ignore_time:
await self.refresh_config()
self.last_update = time.time()

Expand All @@ -47,14 +47,14 @@ async def refresh_config(self):
"""
print("\nRefreshing target configuration...\n")

url = static_stuff.target_configuration_url
url = self.settings.remote_config_url

if url.startswith("http"):
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
json_data = await resp.json()
if resp.status != 200:
print("Error: Could not get config file from " + static_stuff.target_configuration_url)
print("Error: Could not get config file from " + self.settings.remote_config_url)
return

# parse config file
Expand Down
Loading