️ DEPRECATED GITLAB INSTANCE ️ This GitLab is now read-only for reference. Please use https://gitlab.iauro.co for all new work.

Migration completed on September 17, 2025

Commit 0dfa093d authored by Piyush Singh's avatar Piyush Singh

Add Websocket-FastAPI (Module 2) module

parent 00cecae5
# auth.py
from datetime import datetime, timedelta
from jose import JWTError, jwt
from passlib.context import CryptContext
# Secret key (in production load from env)
SECRET_KEY = "8f7c02f1c2a74a7d84d5a07fb5313d53f70c8b99f5f63e7b6c85e9d3f1c1fbbc"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str):
return pwd_context.hash(password)
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
def create_access_token(data: dict, expires_delta: timedelta | None = None):
to_encode = data.copy()
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
def decode_access_token(token: str):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except JWTError:
return None
import json
from datetime import timedelta
from fastapi import FastAPI, Depends, HTTPException, WebSocket, Form, Query,Path
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi.responses import HTMLResponse, RedirectResponse
from pydantic import BaseModel
from auth import hash_password, verify_password, create_access_token, decode_access_token
from typing import Dict
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login")
# Store active websocket connections
active_connections: Dict[str, WebSocket] = {}
USERS_DB = "users.json"
TASKS_DB = "tasks.json"
class User(BaseModel):
username: str
password: str
class Task(BaseModel):
task: str
# --- JSON helpers ---
def load_json(file):
try:
with open(file, "r") as f:
return json.load(f)
except FileNotFoundError:
return {}
def save_json(file, data):
with open(file, "w") as f:
json.dump(data, f, indent=4)
def get_current_user(token: str = Depends(oauth2_scheme)):
payload = decode_access_token(token)
if not payload:
raise HTTPException(status_code=401, detail="Invalid or expired token")
return payload["sub"]
# --- User routes ---
@app.post("/register")
def register(user: User):
users = load_json(USERS_DB)
if user.username in users:
raise HTTPException(status_code=400, detail="Username exists")
users[user.username] = {
"username": user.username,
"password": hash_password(user.password),
}
save_json(USERS_DB, users)
return {"message": "Registered successfully"}
@app.post("/login")
def login(form_data: OAuth2PasswordRequestForm = Depends()):
users = load_json(USERS_DB)
user = users.get(form_data.username)
if not user or not verify_password(form_data.password, user["password"]):
raise HTTPException(status_code=401, detail="Invalid credentials")
# create JWT
token = create_access_token(
{"sub": form_data.username}, expires_delta=timedelta(minutes=30)
)
return {"access_token": token, "token_type": "bearer"}
# ---------- HTML PAGES ----------
@app.get("/", response_class=HTMLResponse)
async def login_page():
with open("static/login.html", "r") as f:
return HTMLResponse(f.read())
@app.get("/register", response_class=HTMLResponse)
async def register_page():
with open("static/register.html", "r") as f:
return HTMLResponse(f.read())
@app.get("/dashboard", response_class=HTMLResponse)
async def dashboard(token: str = Query(None)):
if not token:
return RedirectResponse("/")
payload = decode_access_token(token)
if not payload:
return RedirectResponse("/")
with open("static/HTML-Websocket.html", "r") as f:
return HTMLResponse(f.read())
# --- Task routes ---
@app.get("/tasks")
def get_tasks(current_user: str = Depends(get_current_user)):
tasks_db = load_json(TASKS_DB)
return tasks_db.get(current_user, [])
@app.post("/add-task")
async def add_task(
username: str = Form(...), task: str = Form(...), token: str = Query(None)
):
# Verify token
payload = decode_access_token(token)
if not payload or payload["sub"] != username:
raise HTTPException(status_code=401, detail="Invalid token")
# Save task
data = load_json(TASKS_DB)
if username not in data:
data[username] = []
next_id = len(data[username]) + 1
data[username].append({"id": next_id, "task": task})
save_json(TASKS_DB, data)
# Notify user via WebSocket
if username in active_connections:
try:
await active_connections[username].send_text(f"New Task: {task}")
except Exception:
active_connections.pop(username, None)
return {"message": "Task added successfully"}
@app.post("/delete-task")
async def delete_task(
username: str = Form(...), task_id: int = Form(...), token: str = Query(None)
):
# Verify token
payload = decode_access_token(token)
if not payload or payload["sub"] != username:
raise HTTPException(status_code=401, detail="Invalid token")
# Load tasks
data = load_json(TASKS_DB)
if username not in data:
raise HTTPException(status_code=404, detail="No tasks found for this user")
tasks = data[username]
new_tasks = [t for t in tasks if t["id"] != task_id]
if len(tasks) == len(new_tasks):
raise HTTPException(status_code=404, detail="Task not found")
data[username] = new_tasks
save_json(TASKS_DB, data)
# Notify via WebSocket
if username in active_connections:
try:
await active_connections[username].send_text(f"Task {task_id} deleted")
except Exception:
active_connections.pop(username, None)
return {"message": f"Task {task_id} deleted successfully"}
# --- WebSocket ---
@app.websocket("/ws/{username}")
async def websocket_endpoint(websocket: WebSocket, username: str):
await websocket.accept()
active_connections[username] = websocket
try:
while True:
await websocket.receive_text() # keep alive
#await websocket.send_text("Websocket Connected")
except Exception:
active_connections.pop(username, None)
<!DOCTYPE html>
<html>
<head>
<title>Dashboard</title>
</head>
<body>
<h2>Task Manager (WebSocket)</h2>
<input type="text" id="task" placeholder="Enter task">
<button onclick="addTask()">Add Task</button>
<h3>Your Tasks:</h3>
<ul id="tasks"></ul>
<h3>Notifications:</h3>
<ul id="messages"></ul>
<script>
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get("token");
const username = urlParams.get("username");
if(!token || !username){
alert("Unauthorized. Please login again.");
window.location.href = "/";
}
let ws = new WebSocket(`ws://localhost:8000/ws/${username}`);
ws.onmessage = (event) => {
let li = document.createElement("li");
li.innerText = event.data;
document.getElementById("messages").appendChild(li);
alert("message from Websocket: "+event.data);
loadTasks();
};
ws.onopen = () => {
console.log("WebSocket connection established");
};
function addTask(){
let task = document.getElementById("task").value;
if(!task) return;
fetch(`/add-task?token=${token}`, {
method: "POST",
headers: {"Content-Type": "application/x-www-form-urlencoded"},
body: `username=${username}&task=${task}`
}).then(() => {
document.getElementById("task").value = "";
});
}
function loadTasks(){
fetch(`/tasks?token=${token}`, {
headers: { "Authorization": `Bearer ${token}` }
}).then(res => res.json()).then(tasks => {
const taskList = document.getElementById("tasks");
taskList.innerHTML = "";
tasks.forEach(t => {
let li = document.createElement("li");
li.innerText = `${t.id}. ${t.task} `;
let btn = document.createElement("button");
btn.innerText = "Delete";
btn.onclick = () => deleteTask(t.id);
li.appendChild(btn);
taskList.appendChild(li);
});
});
}
function deleteTask(id){
fetch(`/delete-task?token=${token}`, {
method: "POST",
headers: {"Content-Type": "application/x-www-form-urlencoded"},
body: `username=${username}&task_id=${id}`
}).then(() => loadTasks());
}
window.onload = loadTasks;
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h2>Login</h2>
<form id="loginForm">
<label>Username:</label>
<input type="text" id="username" required><br><br>
<label>Password:</label>
<input type="password" id="password" required><br><br>
<button type="submit">Login</button>
</form>
<p>Don't have an account? <a href="/register">Register here</a></p>
<script>
document.getElementById("loginForm").onsubmit = async function(e){
e.preventDefault();
let username = document.getElementById("username").value;
let password = document.getElementById("password").value;
let res = await fetch("/login", {
method: "POST",
headers: {"Content-Type": "application/x-www-form-urlencoded"},
body: `username=${username}&password=${password}`
});
let data = await res.json();
if(data.access_token){
window.location.href = `/dashboard?token=${data.access_token}&username=${username}`;
} else {
alert("Login failed");
}
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Register</title>
</head>
<body>
<h2>Register</h2>
<form id="registerForm">
<label>Username:</label>
<input type="text" id="username" required><br><br>
<label>Password:</label>
<input type="password" id="password" required><br><br>
<button type="submit">Register</button>
</form>
<p>Already have an account? <a href="/">Login here</a></p>
<script>
document.getElementById("registerForm").onsubmit = async function(e){
e.preventDefault();
let username = document.getElementById("username").value;
let password = document.getElementById("password").value;
let res = await fetch("/register", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({username, password})
});
let data = await res.json();
if(res.ok){
alert("Registered successfully! Please login.");
window.location.href = "/";
} else {
alert("Error: " + data.detail);
}
}
</script>
</body>
</html>
{
"Piyush": [
{
"id": 1,
"task": "Buy milk"
},
{
"id": 2,
"task": "Learn FastAPI"
}
],
"Arya": [
{
"id": 1,
"task": "Buy milk"
},
{
"id": 2,
"task": "Buy curd"
},
{
"id": 5,
"task": "ice-cream"
},
{
"id": 6,
"task": "Eggs"
},
{
"id": 7,
"task": "fish"
},
{
"id": 8,
"task": "Fishing"
},
{
"id": 10,
"task": "Swimming"
},
{
"id": 8,
"task": "Dog"
}
],
"Ryzen": [
{
"id": 1,
"task": "fish"
},
{
"id": 2,
"task": "UPS 95"
}
],
"Alex": [
{
"id": 1,
"task": "fishy"
}
]
}
\ No newline at end of file
{
"Piyush": {
"username": "Piyush",
"password": "$2b$12$Oq9pFPfJFdEaXQz0HrRab.QWg4YkZiC.I/4HxCZCNrxJam31Trhxu"
},
"Arya": {
"username": "Arya",
"password": "$2b$12$1XNFgBVRK4l9xCNDLKCtw.xQCYhymyK8NIFGCzqUdM0aWMBPpAyYC"
},
"Alex": {
"username": "Alex",
"password": "$2b$12$KEsTt9vUonxRktt.GDJmL.Tboo8QsIEKBX01sl946a4IbAp54f1XC"
},
"Ram": {
"username": "Ram",
"password": "$2b$12$tTVy6Cc/clCseRQgvmKW4ON/5/BYk/OCw6XpYzgtpyyvYJ7jk.KNa"
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment