For now? I'm experimenting on an old concept.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Distinct between httplogger and the logger inside websocket connections

+137 -88
+137 -88
server/src/lumina_server.gleam
··· 35 35 import simplifile 36 36 import sqlight 37 37 import woof 38 + import youid/uuid 38 39 39 40 type HandlerContext { 40 41 HandlerContext( ··· 70 71 } 71 72 72 73 type User { 73 - User( 74 - // Todo 75 - Nil, 76 - ) 74 + User(uid: uuid.Uuid, username: String) 77 75 } 78 76 79 77 pub fn main() { ··· 210 208 process.sleep_forever() 211 209 } 212 210 211 + fn handler(req: Request, handler_ctx: HandlerContext) -> Response { 212 + let httplogger = fn( 213 + level: woof.Level, 214 + msg: String, 215 + vars: List(#(String, String)), 216 + ) { 217 + woof.new("SERVER/HTTP") 218 + |> woof.log(level, msg, [ 219 + woof.field("uri path", req.path), 220 + woof.field("request-host", case req.host { 221 + "0.0.0.0" -> "local (unsure)" 222 + d -> d 223 + }), 224 + ..vars 225 + ]) 226 + } 227 + let ok = fn() { httplogger(woof.Info, "200/OK", []) } 228 + case req.path |> uri.path_segments() { 229 + ["/"] | [""] | [] -> { 230 + ok() 231 + handler_ctx.static_responses(RouteForIndex) 232 + } 233 + ["static", "lumina.min.mjs"] -> { 234 + ok() 235 + handler_ctx.static_responses(RouteForClientAsMinifiedJavascript) 236 + } 237 + ["static", "lumina.mjs"] -> { 238 + ok() 239 + handler_ctx.static_responses(RouteForClientAsJavascript) 240 + } 241 + ["static", "lumina.css"] -> { 242 + ok() 243 + handler_ctx.static_responses(RouteForClientStyles) 244 + } 245 + 246 + ["favicon.ico"] | ["static", "logo.png"] -> { 247 + ok() 248 + handler_ctx.static_responses(RouteForIconAsPNG) 249 + } 250 + ["static", "logo.svg"] -> { 251 + ok() 252 + handler_ctx.static_responses(RouteForIconAsSVG) 253 + } 254 + ["connection"] -> { 255 + ewe.upgrade_websocket( 256 + req, 257 + // If ever we need to send messages through processes to get to and from the client over here, we should 258 + // take a second look at the ewe example on 259 + // https://github.com/vshakitskiy/ewe/blob/mistress/examples/src/websocket.gleam 260 + on_init: fn(_conn, selector) { 261 + // Initial state for THIS specific client 262 + let state = 263 + WebsocketState( 264 + ctx: handler_ctx, 265 + conn_data: ClientConnectionData(None, None), 266 + logger: fn( 267 + level: woof.Level, 268 + msg: String, 269 + vars: List(#(String, String)), 270 + conn_data: ClientConnectionData, 271 + ) { 272 + woof.new("WEB/SOCKET:CLIENT") 273 + |> woof.log(level, msg, [ 274 + woof.field("uri path", req.path), 275 + woof.field("request-host", case req.host { 276 + "0.0.0.0" -> "local (unsure)" 277 + d -> d 278 + }), 279 + woof.field( 280 + "user", 281 + conn_data.user 282 + |> option.map(fn(user) { user.username }) 283 + |> option.unwrap("unknown"), 284 + ), 285 + ..vars 286 + ]) 287 + }, 288 + ) 289 + httplogger(woof.Info, "101/PROTOCOL UPGRADE", []) 290 + #(state, selector) 291 + }, 292 + handler: client_communication_handler, 293 + on_close: fn(_conn, _state) { Nil }, 294 + ) 295 + } 296 + _ -> { 297 + httplogger(woof.Warning, "Not found.", []) 298 + response.new(404) 299 + |> response.set_header("content-type", "text/plain; charset=utf-8") 300 + |> response.set_body(ewe.TextData("404! Not found!")) 301 + } 302 + } 303 + } 304 + 305 + type WebsocketState { 306 + WebsocketState( 307 + ctx: HandlerContext, 308 + conn_data: ClientConnectionData, 309 + logger: fn( 310 + woof.Level, 311 + String, 312 + List(#(String, String)), 313 + ClientConnectionData, 314 + ) -> 315 + Nil, 316 + ) 317 + } 318 + 319 + fn client_communication_handler( 320 + _conn: ewe.WebsocketConnection, 321 + state: WebsocketState, 322 + // That Nil is the internal message, again if we'd follow the example. But 323 + // Lumina mostly communicates with the database and stores more global variables in Booklets (which is ETS)... So no need. 324 + message: ewe.WebsocketMessage(Nil), 325 + ) -> ewe.WebsocketNext(WebsocketState, Nil) { 326 + let #(handler_context, connection_data, connection_logger) = { 327 + #( 328 + state.ctx, 329 + state.conn_data, 330 + fn(level: woof.Level, message: String, variables: List(#(String, String))) { 331 + state.logger(level, message, variables, state.conn_data) 332 + }, 333 + ) 334 + } 335 + case message { 336 + ewe.Text(json_str) -> { 337 + connection_logger(woof.Debug, "Received: " <> json_str, []) 338 + // Todo 339 + ewe.websocket_continue(state) 340 + } 341 + ewe.Binary(_) -> ewe.websocket_continue(state) 342 + ewe.User(Nil) -> ewe.websocket_continue(state) 343 + } 344 + } 345 + 213 346 fn static( 214 347 client_hash: String, 215 348 assets: String, ··· 299 432 } 300 433 } 301 434 } 302 - 303 - fn handler(req: Request, handler_ctx: HandlerContext) -> Response { 304 - let httplogger = fn( 305 - level: woof.Level, 306 - msg: String, 307 - vars: List(#(String, String)), 308 - ) { 309 - woof.new("WEBSERVER") 310 - |> woof.log(level, msg, [woof.field("uri path", req.path), ..vars]) 311 - } 312 - case req.path |> uri.path_segments() { 313 - ["/"] | [""] | [] -> { 314 - httplogger(woof.Info, "OK", []) 315 - handler_ctx.static_responses(RouteForIndex) 316 - } 317 - ["static", "lumina.min.mjs"] -> { 318 - httplogger(woof.Info, "OK", []) 319 - handler_ctx.static_responses(RouteForClientAsMinifiedJavascript) 320 - } 321 - ["static", "lumina.mjs"] -> { 322 - httplogger(woof.Info, "OK", []) 323 - handler_ctx.static_responses(RouteForClientAsJavascript) 324 - } 325 - ["static", "lumina.css"] -> { 326 - httplogger(woof.Info, "OK", []) 327 - handler_ctx.static_responses(RouteForClientStyles) 328 - } 329 - 330 - ["favicon.ico"] | ["static", "logo.png"] -> { 331 - httplogger(woof.Info, "OK", []) 332 - handler_ctx.static_responses(RouteForIconAsPNG) 333 - } 334 - ["static", "logo.svg"] -> { 335 - httplogger(woof.Info, "OK", []) 336 - handler_ctx.static_responses(RouteForIconAsSVG) 337 - } 338 - ["connection"] -> { 339 - ewe.upgrade_websocket( 340 - req, 341 - // If ever we need to send messages through processes to get to and from the client over here, we should 342 - // take a second look at the ewe example on 343 - // https://github.com/vshakitskiy/ewe/blob/mistress/examples/src/websocket.gleam 344 - on_init: fn(_conn, selector) { 345 - // Initial state for THIS specific client 346 - let state = 347 - WebsocketState( 348 - ctx: handler_ctx, 349 - conn_data: ClientConnectionData(None, None), 350 - ) 351 - #(state, selector) 352 - }, 353 - handler: client_communication_handler, 354 - on_close: fn(_conn, _state) { Nil }, 355 - ) 356 - } 357 - _ -> { 358 - httplogger(woof.Warning, "Not found.", []) 359 - response.new(404) 360 - |> response.set_header("content-type", "text/plain; charset=utf-8") 361 - |> response.set_body(ewe.TextData("404! Not found!")) 362 - } 363 - } 364 - } 365 - 366 - type WebsocketState { 367 - WebsocketState(ctx: HandlerContext, conn_data: ClientConnectionData) 368 - } 369 - 370 - fn client_communication_handler( 371 - _conn: ewe.WebsocketConnection, 372 - state: WebsocketState, 373 - // That Nil is the internal message, again if we'd follow the example. But 374 - // Lumina mostly communicates with the database and stores more global variables in Booklets (which is ETS)... So no need. 375 - message: ewe.WebsocketMessage(Nil), 376 - ) -> ewe.WebsocketNext(WebsocketState, Nil) { 377 - case message { 378 - ewe.Text(json_str) -> { 379 - // Todo 380 - ewe.websocket_continue(state) 381 - } 382 - ewe.Binary(_) -> ewe.websocket_continue(state) 383 - ewe.User(Nil) -> ewe.websocket_continue(state) 384 - } 385 - }