summaryrefslogtreecommitdiff
path: root/ws.go (follow)
Commit message (Collapse)AuthorAgeFilesLines
* {config,ws}.go, cca.scfg.example: Allow same-user fake authRunxi Yu13 days1-7/+15
| | | | This is useful for testing whether connection collisions work well.
* ws.go: Don't log chanPool changesRunxi Yu13 days1-2/+0
|
* {ws,wsm}.go: Handle context cancellationsRunxi Yu14 days1-5/+74
|
* ws.go: Fix memory leak introduced in last commitRunxi Yu14 days1-0/+7
| | | | | | The entry is deleted from cancelPool if and only if cancelPool's cancel function for the user is equal to &newCancel. This compare-and-delete works because of locking.
* ws.go: Fix first race condition in cancelPool managementRunxi Yu14 days1-13/+2
| | | | | | | | | | | | | | | Cancel occurs in async. When the cancelled function exits, it deletes the entry in cancelPool, and could replace the new routine's cancel function, which is of course undesirable. Therefore this commit causes handleConn to stop deleting from cancelPool entirely. Note that this introduces a memory leak at the size of context.CancelFunc per user, because we are never deleting from cancelPool. This does not actually solve the race condition documented in fc911928 where two new connections start sufficiently close to each other.
* {main,ws,wsm}.go: Attempt to cancel old sessionsRunxi Yu14 days1-8/+66
| | | | | | | | | | | | | | | | | | | When beginning to handle a WebSocket connection, we shall create a new context, with the request context as its parent. We use the new context for everything from now on, except for reporting error messages, which is handled by creating a reportError function in a closure in makeReportError and passing it along to command-handling functions. Note that if one user attempts to rapidly launch WebSocket connections, there might still be a race condition where the old connection hasn't been completely established yet (i.e. an entry hasn't been added to cancelPool) and the new connection isn't able to cancel the old connection. I'm a bit tired to think of a solution now but it could probably be solved by moving the cancellation registration and cancelling sooner during the initial handshake. Note that more parts of the event loop needs to select from ctx.Done (from newCtx) for this to work reliably.
* ws.go: Update comment on disallowed charactersRunxi Yu2024-10-021-5/+4
|
* {auth,utils,ws}.go: randomBytes -> randomStringRunxi Yu2024-10-021-1/+1
|
* {config,ws}.go, cca.scfg.example: Add fake auth supportRunxi Yu2024-10-021-16/+61
| | | | | Fake authentication is useful when benchmarking the server with an external program without going insane with the OpenID Connect forms.
* {ws,wsm}.go: Split message handlers into their own functionsRunxi Yu2024-10-011-124/+5
|
* {auth,ws}.go: Remove unnecessary TODOsRunxi Yu2024-10-011-14/+2
|
* ws.go: Allow deselecting coursesRunxi Yu2024-10-011-0/+34
|
* ws.go: Fix logic error when reaffirming a course choiceRunxi Yu2024-10-011-2/+2
| | | | | | | | | | | | | | When a user has already chosen a course choice but sends a message to choose it again, a database error occurs as the uniqueness constraint is violated. In this case, we "reaffirm" the user's course choice, to hopefully get their client's state back in sync. However, we previously forgot to return back to the event loop after this reaffirmation, causing the control flow to fall into the course-increment and transaction-commit stage. The error is discovered at tx.Commit, where pgx raises a ErrTxCommitRollback, because in that case we're trying to commit a transaction that has already encountered an error.
* ws.go: protocolError instead of R on unexpected database errorsRunxi Yu2024-10-011-23/+7
| | | | | | | When an unknown database error is encoutered, the connection should be considered broken and the error should be reported as a fatal error to the end user. Rejecting the course choice unsets the checkbox and lets the page to be continued to be used, which is not intended.
* index.go, ws.go: Fix race condition surrounding coursesRunxi Yu2024-10-011-1/+5
| | | | | | handleIndex and handleConn used to access the courses map without RLock'ing coursesLock, which may cause issues if courses is being written to, by a function such as setupCourses.
* ws.go: Decrement course.Selected counter on commit failuresRunxi Yu2024-10-011-0/+6
|
* ws.go: Reaffirm course choice when duplicate is requestedRunxi Yu2024-10-011-5/+13
| | | | | | | | Laggy clients, extremely fast clicks, or other conditions could cause duplicate course choices to be sent, which would violate the uniqueness constraint. In this case the fact that the user has already chosen the course should be reaffirmed, rather than making it look like their choice was rejected.
* ws.go: propagateCouldFail -> propagateIgnoreFailuresRunxi Yu2024-10-011-2/+2
| | | | | | I think the new name better reflects the fact that it just ignores failures when propagating to each channel. The old name sounds like "this function itself could fail".
* ws.go, schema.sql: Enforce uniqueness of course choicesRunxi Yu2024-10-011-42/+64
| | | | References: https://todo.sr.ht/~runxiyu/cca/1
* ws.go, *.sql: Add course choices to the databaseRunxi Yu2024-10-011-1/+33
| | | | | | | | | | | | | | | | | | | | Note that this naive implementation currently allows users to submit multiple requests for the same course. See the TODO comment below: /* * TODO: Ensure that the user is not already enrolled in this course * and pay attention to relevant race conditions. It might be useful * to restructure this part, to begin a transaction that adds the user * to the database (and check the (currently not existing) uniqueness) * constraint at that exact moment, and abort the transaction if the * course limit is exceeded. * Or perhaps choices should be also stored in an internal data * structure, though that requires extra attention on consistency * issues between the internal data structure and the database. * (Sometime I should really go fix the LMDB bindings...) */ References: https://todo.sr.ht/~runxiyu/cca/1
* ws.go: propagate -> propagateCouldFailRunxi Yu2024-10-011-3/+8
|
* ws.go: propagate course number updates in another goroutineRunxi Yu2024-10-011-1/+1
|
* ws.go: Separate c.Write calls into writeText()Runxi Yu2024-09-301-25/+17
|
* ws.go, utils.go: Document some synchronization design choicesRunxi Yu2024-09-301-1/+18
| | | | Also use TryLock in setupChanPool, and fail when not successful.
* *: Change license to AGPL-3.0-or-laterRunxi Yu2024-09-301-21/+11
|
* {auth,index,ws}.go, schema.sql: Move session cookie into the user tableRunxi Yu2024-09-301-8/+8
| | | | | | | One user shall only have one session at a time. This reduces the possibility of strange race conditions and simplifies the code a lot. References: https://todo.sr.ht/~runxiyu/cca/4
* index.html, main.js, ws.go: Enhance course selection rejection messageRunxi Yu2024-09-301-1/+1
|
* ws.go, config.go, config.scfg.example: Attempt to fix deadlockRunxi Yu2024-09-291-4/+7
| | | | | | | When propagate tries to propagate a message to a connection that actually called propagate, it deadlocks because the it tries to send to that connection's send channel in the same goroutine. This is an attempt at a fix.
* ws.go: Attempt to propagate messagesRunxi Yu2024-09-291-1/+11
|
* ws.go: Implement course choice limitsRunxi Yu2024-09-291-0/+31
|
* ws.go: protocolError is now its own functionRunxi Yu2024-09-291-28/+15
|
* .ws.go: Close websocket on protocol errorsRunxi Yu2024-09-291-0/+12
|
* ws.go: Stub for commands "Y" and "N", currently only counting argumentsRunxi Yu2024-09-291-0/+14
|
* ws.go: chanPoolLock should be locked during setupChanPoolRunxi Yu2024-09-271-0/+2
|
* ws.go: chanPool should be a map tooRunxi Yu2024-09-271-19/+8
|
* *.go, cca.scfg.example: Expose performance optionsRunxi Yu2024-09-261-3/+3
|
* *.go: Wrap errorsRunxi Yu2024-09-261-3/+4
|
* {auth,index,ws}.go: Add contexts for database callsRunxi Yu2024-09-261-1/+1
|
* ws.go: ReformatRunxi Yu2024-09-261-1/+1
|
* ws.go: Document chanPoolLock's purposeRunxi Yu2024-09-241-0/+9
|
* *.go: LintingRunxi Yu2024-09-241-14/+20
|
* {index,utils,ws}.go: Handle write errorsRunxi Yu2024-09-241-8/+28
|
* {utils,auth,index,ws}.go: Handle errors in random number generationRunxi Yu2024-09-241-1/+1
|
* ws.go: Log userid and sessionid with channel pointerRunxi Yu2024-09-241-3/+4
|
* ws.go: chanPoolLock should be a RWMutex rather than a pointer to oneRunxi Yu2024-09-231-1/+1
| | | | | | | A pointer to one could always be obtained via &chanPoolLock; but if I declare it as a pointer globally, I would need to initialize it somewhere so I don't get a null pointer dereference. It's more convenient to just declare it as the value.
* ws.go: Add missing returns after authentication failureRunxi Yu2024-09-231-0/+2
|
* ws.go: Initial attempt to manage chanPoolRunxi Yu2024-09-231-13/+22
|
* auth.go, ws.go: Update commentsRunxi Yu2024-09-231-5/+5
|
* ws.go, main.js, index.html: Better WS documentation and structureRunxi Yu2024-09-161-19/+55
|
* ws.go: Fix previous commit's type inconsistenciesRunxi Yu2024-09-131-4/+5
|