mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-28 08:44:06 +02:00
cx thread safe
This commit is contained in:
parent
f7d6ec9d91
commit
b3d911685e
@ -12,13 +12,6 @@ void route_get_cart_items_from_session(HttpCtx* ctx)
|
|||||||
CartItemVec cart_items;
|
CartItemVec cart_items;
|
||||||
cart_item_vec_construct(&cart_items);
|
cart_item_vec_construct(&cart_items);
|
||||||
|
|
||||||
DbRes db_res
|
|
||||||
= db_cart_items_with_user_id(cx->db, &cart_items, session->user_id);
|
|
||||||
if (db_res != DbRes_Ok) {
|
|
||||||
RESPOND_BAD_REQUEST(ctx, "Could not find cart for user");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String res;
|
String res;
|
||||||
string_construct(&res);
|
string_construct(&res);
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "../db/db.h"
|
#include "../db/db.h"
|
||||||
#include "../http/http.h"
|
#include "../http/http.h"
|
||||||
|
#include <pthread.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -16,16 +17,20 @@ void session_destroy(Session* session);
|
|||||||
|
|
||||||
DEFINE_VEC(Session, SessionVec, session_vec, 16)
|
DEFINE_VEC(Session, SessionVec, session_vec, 16)
|
||||||
|
|
||||||
void sessions_remove(SessionVec* vec, int64_t user_id);
|
|
||||||
Session* sessions_add(SessionVec* vec, int64_t user_id);
|
|
||||||
const Session* sessions_find(SessionVec* vec, const char* token);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
pthread_mutex_t mutex;
|
||||||
int number;
|
int number;
|
||||||
SessionVec sessions;
|
SessionVec sessions;
|
||||||
Db* db;
|
Db* db;
|
||||||
} Cx;
|
} Cx;
|
||||||
|
|
||||||
|
void cx_construct(Cx* cx, Db* db);
|
||||||
|
void cx_destroy(Cx* cx);
|
||||||
|
|
||||||
|
void cx_sessions_remove(Cx* cx, int64_t user_id);
|
||||||
|
Session* cx_sessions_add(Cx* cx, int64_t user_id);
|
||||||
|
const Session* cx_sessions_find(Cx* cx, const char* token);
|
||||||
|
|
||||||
void route_get_index(HttpCtx* ctx);
|
void route_get_index(HttpCtx* ctx);
|
||||||
void route_post_set_number(HttpCtx* ctx);
|
void route_post_set_number(HttpCtx* ctx);
|
||||||
void route_get_not_found(HttpCtx* ctx);
|
void route_get_not_found(HttpCtx* ctx);
|
||||||
|
95
backend/src/controllers/cx.c
Normal file
95
backend/src/controllers/cx.c
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include "../util/str.h"
|
||||||
|
#include "controllers.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
void session_construct(Session* session, int64_t user_id)
|
||||||
|
{
|
||||||
|
char* token = str_random(64);
|
||||||
|
size_t token_hash = str_fast_hash(token);
|
||||||
|
*session = (Session) { user_id, token, token_hash };
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_destroy(Session* session)
|
||||||
|
{
|
||||||
|
free(session->token);
|
||||||
|
*session = (Session) {
|
||||||
|
.user_id = 0,
|
||||||
|
.token = NULL,
|
||||||
|
.token_hash = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void cx_construct(Cx* cx, Db* db)
|
||||||
|
{
|
||||||
|
*cx = (Cx) {
|
||||||
|
.mutex = PTHREAD_MUTEX_INITIALIZER,
|
||||||
|
.number = 1,
|
||||||
|
.sessions = (SessionVec) { 0 },
|
||||||
|
.db = db,
|
||||||
|
};
|
||||||
|
session_vec_construct(&cx->sessions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cx_destroy(Cx* cx)
|
||||||
|
{
|
||||||
|
pthread_mutex_destroy(&cx->mutex);
|
||||||
|
session_vec_destroy(&cx->sessions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cx_sessions_remove(Cx* cx, int64_t user_id)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&cx->mutex);
|
||||||
|
|
||||||
|
SessionVec* vec = &cx->sessions;
|
||||||
|
for (size_t i = 0; i < vec->size; ++i) {
|
||||||
|
if (vec->data[i].user_id == user_id) {
|
||||||
|
session_destroy(&vec->data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&cx->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Session* cx_sessions_add(Cx* cx, int64_t user_id)
|
||||||
|
{
|
||||||
|
Session* res;
|
||||||
|
pthread_mutex_lock(&cx->mutex);
|
||||||
|
|
||||||
|
SessionVec* vec = &cx->sessions;
|
||||||
|
for (size_t i = 0; i < vec->size; ++i) {
|
||||||
|
if (vec->data[i].user_id == 0) {
|
||||||
|
session_construct(&vec->data[i], user_id);
|
||||||
|
res = &vec->data[i];
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Session session;
|
||||||
|
session_construct(&session, user_id);
|
||||||
|
session_vec_push(vec, session);
|
||||||
|
|
||||||
|
res = &vec->data[vec->size - 1];
|
||||||
|
|
||||||
|
l0_return:
|
||||||
|
pthread_mutex_unlock(&cx->mutex);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Session* cx_sessions_find(Cx* cx, const char* token)
|
||||||
|
{
|
||||||
|
const Session* res;
|
||||||
|
pthread_mutex_lock(&cx->mutex);
|
||||||
|
|
||||||
|
SessionVec* vec = &cx->sessions;
|
||||||
|
size_t token_hash = str_fast_hash(token);
|
||||||
|
for (size_t i = 0; i < vec->size; ++i) {
|
||||||
|
if (vec->data[i].token_hash == token_hash) {
|
||||||
|
res = &vec->data[i];
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res = NULL;
|
||||||
|
|
||||||
|
l0_return:
|
||||||
|
pthread_mutex_unlock(&cx->mutex);
|
||||||
|
return res;
|
||||||
|
}
|
@ -41,8 +41,8 @@ void route_post_sessions_login(HttpCtx* ctx)
|
|||||||
goto l2_return;
|
goto l2_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sessions_remove(&cx->sessions, user.id);
|
cx_sessions_remove(cx, user.id);
|
||||||
Session* session = sessions_add(&cx->sessions, user.id);
|
Session* session = cx_sessions_add(cx, user.id);
|
||||||
|
|
||||||
RESPOND_JSON(ctx, 200, "{\"ok\":true,\"token\":\"%s\"}", session->token);
|
RESPOND_JSON(ctx, 200, "{\"ok\":true,\"token\":\"%s\"}", session->token);
|
||||||
l2_return:
|
l2_return:
|
||||||
@ -59,7 +59,7 @@ void route_post_sessions_logout(HttpCtx* ctx)
|
|||||||
RESPOND_JSON(ctx, 200, "{\"ok\":true}");
|
RESPOND_JSON(ctx, 200, "{\"ok\":true}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sessions_remove(&cx->sessions, session->user_id);
|
cx_sessions_remove(cx, session->user_id);
|
||||||
RESPOND_JSON(ctx, 200, "{\"ok\":true}");
|
RESPOND_JSON(ctx, 200, "{\"ok\":true}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ const Session* header_session(HttpCtx* ctx)
|
|||||||
}
|
}
|
||||||
const char* token = http_ctx_req_headers_get(ctx, "Session-Token");
|
const char* token = http_ctx_req_headers_get(ctx, "Session-Token");
|
||||||
// session expiration should be handled here
|
// session expiration should be handled here
|
||||||
return sessions_find(&cx->sessions, token);
|
return cx_sessions_find(cx, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns NULL AND responds if no valid session is found.
|
// Returns NULL AND responds if no valid session is found.
|
||||||
@ -105,54 +105,3 @@ const Session* middleware_session(HttpCtx* ctx)
|
|||||||
}
|
}
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_construct(Session* session, int64_t user_id)
|
|
||||||
{
|
|
||||||
char* token = str_random(64);
|
|
||||||
size_t token_hash = str_fast_hash(token);
|
|
||||||
*session = (Session) { user_id, token, token_hash };
|
|
||||||
}
|
|
||||||
|
|
||||||
void session_destroy(Session* session)
|
|
||||||
{
|
|
||||||
free(session->token);
|
|
||||||
*session = (Session) {
|
|
||||||
.user_id = 0,
|
|
||||||
.token = NULL,
|
|
||||||
.token_hash = 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void sessions_remove(SessionVec* vec, int64_t user_id)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < vec->size; ++i) {
|
|
||||||
if (vec->data[i].user_id == user_id) {
|
|
||||||
session_destroy(&vec->data[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Session* sessions_add(SessionVec* vec, int64_t user_id)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < vec->size; ++i) {
|
|
||||||
if (vec->data[i].user_id == 0) {
|
|
||||||
session_construct(&vec->data[i], user_id);
|
|
||||||
return &vec->data[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Session session;
|
|
||||||
session_construct(&session, user_id);
|
|
||||||
session_vec_push(vec, session);
|
|
||||||
return &vec->data[vec->size - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
const Session* sessions_find(SessionVec* vec, const char* token)
|
|
||||||
{
|
|
||||||
size_t token_hash = str_fast_hash(token);
|
|
||||||
for (size_t i = 0; i < vec->size; ++i) {
|
|
||||||
if (vec->data[i].token_hash == token_hash) {
|
|
||||||
return &vec->data[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
@ -29,6 +29,3 @@ DbRes db_user_with_email(Db* db, User* user, const char* email);
|
|||||||
|
|
||||||
/// Expects `vec` to be constructed.
|
/// Expects `vec` to be constructed.
|
||||||
DbRes db_product_all(Db* db, ProductVec* vec);
|
DbRes db_product_all(Db* db, ProductVec* vec);
|
||||||
|
|
||||||
__attribute__((deprecated("store in memory instead"))) DbRes
|
|
||||||
db_cart_items_with_user_id(Db* db, CartItemVec* vec, int64_t user_id);
|
|
||||||
|
@ -279,44 +279,3 @@ l0_return:
|
|||||||
DISCONNECT;
|
DISCONNECT;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
DbRes db_cart_items_with_user_id(Db* db, CartItemVec* vec, int64_t user_id)
|
|
||||||
{
|
|
||||||
static_assert(sizeof(CartItem) == 32, "model has changed");
|
|
||||||
|
|
||||||
sqlite3* connection;
|
|
||||||
CONNECT;
|
|
||||||
DbRes res;
|
|
||||||
|
|
||||||
sqlite3_stmt* stmt;
|
|
||||||
int sqlite_res;
|
|
||||||
|
|
||||||
sqlite_res = sqlite3_prepare_v2(connection,
|
|
||||||
"SELECT id, user, product, amount FROM cart_items WHERE user = ?",
|
|
||||||
-1,
|
|
||||||
&stmt,
|
|
||||||
NULL);
|
|
||||||
sqlite3_bind_int64(stmt, 1, user_id);
|
|
||||||
|
|
||||||
while ((sqlite_res = sqlite3_step(stmt)) == SQLITE_ROW) {
|
|
||||||
CartItem cart_item = {
|
|
||||||
.id = GET_INT(0),
|
|
||||||
.user_id = GET_INT(1),
|
|
||||||
.product_id = GET_INT(2),
|
|
||||||
.amount = GET_INT(3),
|
|
||||||
};
|
|
||||||
cart_item_vec_push(vec, cart_item);
|
|
||||||
}
|
|
||||||
if (sqlite_res != SQLITE_DONE) {
|
|
||||||
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
|
||||||
res = DbRes_Error;
|
|
||||||
goto l0_return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = DbRes_Ok;
|
|
||||||
l0_return:
|
|
||||||
if (stmt)
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
DISCONNECT;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
@ -24,11 +24,8 @@ int main(void)
|
|||||||
|
|
||||||
Db* db = db_sqlite_new();
|
Db* db = db_sqlite_new();
|
||||||
|
|
||||||
Cx cx = {
|
Cx cx;
|
||||||
.number = 1,
|
cx_construct(&cx, db);
|
||||||
.db = db,
|
|
||||||
};
|
|
||||||
session_vec_construct(&cx.sessions);
|
|
||||||
|
|
||||||
server = http_server_new((HttpServerOpts) {
|
server = http_server_new((HttpServerOpts) {
|
||||||
.port = 8080,
|
.port = 8080,
|
||||||
@ -59,6 +56,7 @@ int main(void)
|
|||||||
http_server_listen(server);
|
http_server_listen(server);
|
||||||
|
|
||||||
http_server_free(server);
|
http_server_free(server);
|
||||||
|
cx_destroy(&cx);
|
||||||
db_sqlite_free(db);
|
db_sqlite_free(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user