Skip to content

Commit

Permalink
Websocket setup (#96)
Browse files Browse the repository at this point in the history
* requirements: import flask-socketio

* backend: socket io

* add socket.io to angular

* add socket-flask to requirment.txt.

* add socket test code in angular

* socket working

* create routers folder

* import other blueprint

* move populate in backend folder

* requirements: hotfix jwt

vimalloc/flask-jwt-extended#557

* Revert "revert me: remove angular"

This reverts commit 9072317.

* docs: debug

* app: add images

---------

Co-authored-by: @ <@>
Co-authored-by: Robin Burri <robinburri@tutanota.com>
  • Loading branch information
t-h2o and RobinBurri authored Nov 19, 2024
1 parent 87c0111 commit aa3d880
Show file tree
Hide file tree
Showing 17 changed files with 175 additions and 26 deletions.
14 changes: 14 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,17 @@ WSGI:: https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface[Web Server Gat
* https://flask.palletsprojects.com/en/3.0.x/quickstart/[Flask] as WSGI
* https://www.psycopg.org/[psycopg] as adapter between Python and PostgreSQL
* https://black.readthedocs.io/en/stable/index.html#[black] as code formatter

=== Debug

=== JWT Error: Subject must be a string!

https://github.com/vimalloc/flask-jwt-extended/issues/557[Issue]

Fix with this https://github.com/vimalloc/flask-jwt-extended/issues/557#issuecomment-2483530464[comment]

____
So quickfix is to add
PyJWT==2.9.0
at the top of your requirements.txt file
____
2 changes: 1 addition & 1 deletion backend/Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ EXPOSE 5000
ENV FLASK_APP=matcha
ENV FLASK_RUN_HOST=0.0.0.0

CMD ["/usr/local/bin/flask", "run"]
CMD ["flask", "--debug", "run", "--host=0.0.0.0", "--port=5000"]
74 changes: 56 additions & 18 deletions backend/matcha/__init__.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,73 @@
from os import environ

from flask import Flask

from flask_socketio import SocketIO
from flask_cors import CORS
from os import environ
from flask_jwt_extended import JWTManager

from flask_jwt_extended import (
JWTManager,
)

from matcha import users
from matcha import auth
from matcha import images
from matcha import interests
from matcha import pictures
from matcha.routers import users
from matcha.routers import auth
from matcha.routers import interests
from matcha.routers import pictures
from matcha.routers import images


def create_app():
app = Flask(__name__)

app.config["JWT_SECRET_KEY"] = environ["FLASK_JWT_SECRET_KEY"]
app.config["UPLOAD_FOLDER"] = environ["FLASK_UPLOAD_FOLDER"]
app.config["URL"] = environ["FLASK_URL"]

CORS(app, origins="http://localhost:4200")

jwt = JWTManager(app)
app.config["SECRET_KEY"] = "your_secret_key"

app.register_blueprint(users.bp)
app.register_blueprint(auth.bp)
app.register_blueprint(images.bp)
app.register_blueprint(interests.bp)
app.register_blueprint(pictures.bp)
app.register_blueprint(images.bp)

CORS(
app,
resources={
r"/*": {
"origins": ["http://localhost:4200"],
"allow_credentials": True,
"methods": ["GET", "POST", "DELETE", "PUT", "OPTIONS"],
}
},
)

socketio = SocketIO(
app,
cors_allowed_origins="http://localhost:4200",
async_mode="threading",
ping_timeout=60000,
logger=True,
engineio_logger=True,
)

jwt = JWTManager(app)

@socketio.on("connect")
def handle_connect():
print("Client connected")

@socketio.on("disconnect")
def handle_disconnect():
print("Client disconnected")

@socketio.on_error()
def error_handler(e):
print("SocketIO error:", str(e))

@socketio.on("message")
def handle_message(data):
try:
print("Received message:", data)
socketio.emit("response", "Server received your message: " + str(data))
except Exception as e:
print("Error handling message:", str(e))
print("Error handling message:", str(e))

return app


# Create a separate run file, say run.py in the backend directory
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
3 changes: 3 additions & 0 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
PyJWT==2.9.0
Flask==3.0.3
psycopg2-binary==2.9.9
flask-cors==5.0.0
flask-socketio==5.4.1
pylint==3.3.1
black==24.10.0
Flask-JWT-Extended==4.6.0
gunicorn==20.1.0
flask-socketio==5.4.1
2 changes: 1 addition & 1 deletion docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ services:
- CHOKIDAR_USEPOLLING=true
env_file:
- .env
command: /usr/local/bin/flask run --host=0.0.0.0 --debug --reload
command: flask --debug run --host=0.0.0.0 --port=5000
depends_on:
- postgres
networks:
Expand Down
43 changes: 37 additions & 6 deletions frontend/AngularApp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/AngularApp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@angular/platform-browser-dynamic": "^18.2.0",
"@angular/router": "^18.2.0",
"rxjs": "~7.8.0",
"socket.io-client": "^4.8.1",
"tslib": "^2.3.0",
"zone.js": "~0.14.10"
},
Expand Down
1 change: 1 addition & 0 deletions frontend/AngularApp/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<div class="page-container">
<app-navbar [onLogout]="logoutHandler"></app-navbar>
<button (click)="sendMessage()">Send Message</button>
<div class="main">
<router-outlet />
</div>
Expand Down
8 changes: 8 additions & 0 deletions frontend/AngularApp/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { NavbarComponent } from './UI/navbar/navbar.component';
import { AuthService } from './auth/auth.service';
import { ErrorService } from './shared/services/error.service';
import { ErrorModalComponent } from './shared/modal/error-modal/error-modal.component';
import { SocketService } from './shared/services/socket.service';

@Component({
selector: 'app-root',
Expand All @@ -22,6 +23,13 @@ export class AppComponent implements OnInit {
private authService = inject(AuthService);
private errorService = inject(ErrorService);

// For testing purposes (next 4 lines)
constructor(private socketService: SocketService) {}
sendMessage() {
console.log('clicked');
this.socketService.sendMessage('Hello from Angular!');
}

error = this.errorService.error;

ngOnInit() {
Expand Down
51 changes: 51 additions & 0 deletions frontend/AngularApp/src/app/shared/services/socket.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Injectable } from '@angular/core';
import { Socket, io } from 'socket.io-client';
import { Observable } from 'rxjs';
import { environment } from '../../../environments/environment';

@Injectable({
providedIn: 'root',
})
export class SocketService {
private socket: Socket;

constructor() {
this.socket = io(environment.websocketUrl, {
withCredentials: true,
transports: ['websocket', 'polling'],
autoConnect: true,
});

// Connection event handlers
this.socket.on('connect', () => {
console.log('Connected to WebSocket server');
});

this.socket.on('connect_error', (error) => {
console.error('WebSocket connection error:', error);
});

this.socket.on('disconnect', (reason) => {
console.log('Disconnected from WebSocket server:', reason);
});
}

sendMessage(message: string): void {
console.log('Sending message:', message);
this.socket.emit('message', message);
}

getResponse(): Observable<any> {
return new Observable((observer) => {
this.socket.on('response', (data) => {
observer.next(data);
});
});
}

ngOnDestroy() {
if (this.socket) {
this.socket.disconnect();
}
}
}
1 change: 1 addition & 0 deletions frontend/AngularApp/src/environments/environment.prod.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const environment = {
production: true,
apiUrl: 'http://localhost/api',
websocketUrl: 'http://localhost:5001',
};
1 change: 1 addition & 0 deletions frontend/AngularApp/src/environments/environment.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const environment = {
production: false,
apiUrl: 'http://localhost:5001/api',
websocketUrl: 'http://localhost:5001',
};

0 comments on commit aa3d880

Please sign in to comment.