-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Obsługa sesji użytkownika i refactoring #10
base: master
Are you sure you want to change the base?
Conversation
…code to use classes;
…e and id from database;
… is used on forum production; Update ws library;
…mentations; Get user id from Q2A and match it with remaining user/socket-client metadata; Further ESLint fixes;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Jak dla mnie ok, ale najlepiej jakby na kod więcej zerknął ktoś od JSa
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potrzebne są zmiany w części serwera http. Osobiście uważam, że ten refactor wprowadza więcej zamieszania niż rozwiązań. Co do części WS - mogłoby tak zostać jak jest. Proponuje przemyśleć migracje na socket.io, kod powinien się uprościć 5-10 razy w stosunku do tego co jest teraz.
{ | ||
method: 'all', | ||
path: '*', | ||
listener: HttpServer.onAll, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handler dla nieobsługiwanych route'ów powinien być zarejestrowany jako ostatni żeby uniknąć konfliktów przy routingu.
static onAll(req, res, next) { | ||
if (req.headers.token !== config.token) { | ||
res.sendStatus(HTTP_STATUS_CODES.FORBIDDEN); | ||
return; | ||
} | ||
|
||
if (req.method !== 'POST') { | ||
res.sendStatus(HTTP_STATUS_CODES.METHOD_NOT_ALLOWED); | ||
return; | ||
} | ||
|
||
next(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Łamie SRP. Pierwszy IF jest middleware'em uwierzytelniającym, powinien być zarejestrowany jako app.use i być zarejestrowanym przed pozostałymi handlerami
- Drugi If powinien być osobnym handlerem, w expressie się obsługuje taką sytuacje w inny sposob, np
app.get('/products', ....);
app.post('/products', ...);
// ważna jest kolejność - jest jako ostatni
app.all('/products', (req, res, next) => { res.status(405).send('Method not allowed'); });
middlewareList.forEach(({ method, path, listener }) => { | ||
if (!method || !path || !listener) { | ||
throw ReferenceError(` | ||
middleware must contain: method, path and listener params! | ||
Received method: "${method}", path: "${path}", listener: "${listener}" | ||
`); | ||
} | ||
|
||
this.app[method](path, listener); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moim zdaniem to jest przekombinowane, w expressie kolejność middleware/handler-ów ma kluczowe znaczenie. Taki sposób tworzenia serwera wprowadza większe zamieszanie niż z tego jest pożytek.
}, | ||
]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Teoretycznie brakuje handlera dla 404 oraz handlera błędów.
this.SUBPAGE_VISITORS_AMOUNT_MAP = (() => { | ||
// create pure object, without prototype | ||
const visitorsMap = Object.create(null); | ||
|
||
return { | ||
incrementIfExists(subPageName) { | ||
if (!(subPageName in visitorsMap)) { | ||
visitorsMap[subPageName] = 0; | ||
} | ||
|
||
visitorsMap[subPageName]++; | ||
}, | ||
decrementAndEventuallyRemove(subPageName) { | ||
if (!(subPageName in visitorsMap) || visitorsMap[subPageName] === 0) { | ||
throw Error(` | ||
visitorsMap does not have property subPageName or it's value is 0! | ||
visitorsMap entries: "${Object.entries(visitorsMap)}", subPageName: "${subPageName}" | ||
`); | ||
} | ||
|
||
visitorsMap[subPageName]--; | ||
|
||
if (visitorsMap[subPageName] === 0) { | ||
delete visitorsMap[subPageName]; | ||
} | ||
}, | ||
}; | ||
})(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
W zasadzie to takie coś jest już zaimplementowane i dostępne chociażby z socket.io - https://socket.io/docs/v4/rooms/. Ale to by wymagało też zmian po stronie klienta, więc może na nowym froncie ;)
@d-bend dziękuję za code review. Poprawki wprowadzę później, gdy wrócę do tego PR-a. Póki co zmieniłem go na draft. |
Częściowo powiązane z: CodersCommunity/forum.pasja-informatyki.local#275
Sesja użytkownika obsługiwana jest poprzez automatyczne wysłanie ciastka z property
qa_session
w trakcie inicjacji WebSocketu przez przeglądarkę. Node następnie pobiera z Q2A identyfikator użytkownika na podstawie otrzymanego ciastka i dzięki temu może identyfikować, do których użytkowników wysyłać konkretne powiadomienia, które są wysyłane przez Q2A w postaci eventów.Przy okazji zrefaktorowałem trochę kod: serwery HTTP i WebSocket rozdzieliłem na osobne klasy, które reprezentują wysoko i nisko (suffix "Core" w nazwie klasy) poziomowe implementacje. Nie jestem pewien czy wyszło dobrze, ale myślę, że to ułatwi orientację, w którym miejscu jest kod służący do dodawania lub rozszerzania ficzerów, a w którym konfiguracja i inicjacja samego połączenia.
Dodałem też ESLint'a i ustawiłem Babel'a, aby targetem budowania kodu był Node v11.9, którego mamy na produkcji. Dzięki temu m.in. kod
async
/await
nie jest transpilowany (pojawiły mi się błędy z brakiem pollyfilowych generatorów dla wspomnianegoasync
/await
) i całościowo/dist
jest mniejszy.