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

Configure Feed

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

WebAPI now supplies the client type

MLC Bloeiman (Jul 9, 2026, 9:49 PM +0200) d0873b52 6355444a

+47 -53
-18
backend/impl-gleam/server/dev/devmode.gleam
··· 1 - import gleam/string 2 - import simplifile 3 - import sqlight 4 - 5 - /// This will generate the testing username-password combinations defined in the README, as well 6 - /// as a `/data/debug` file, which sets log levels to... Yup! To debug instead of Info 7 - pub fn main() { 8 - case simplifile.create_file("../data/configvars/debug") { 9 - Ok(..) | Error(simplifile.Eexist) -> Nil 10 - Error(fuck) -> { 11 - let fucking_error = string.inspect(fuck) 12 - panic as fucking_error 13 - } 14 - } 15 - use db <- sqlight.with_connection("../data/instance.db") 16 - // todo as "The database changes for creating a user are yet unknown." 17 - Nil 18 - }
+21 -10
backend/impl-gleam/server/src/lumina_server.gleam
··· 35 35 import lumina_server/database/events 36 36 import simplifile 37 37 import sqlight 38 - import webapi 38 + import webapi.{WebClient} 39 39 import woof 40 40 import youid/uuid 41 41 ··· 62 62 63 63 type ClientConnectionData { 64 64 ClientConnectionData( 65 - client_type: option.Option(ClientType), 65 + client_type: option.Option(webapi.Clients), 66 66 user: option.Option(User), 67 67 ) 68 - } 69 - 70 - type ClientType { 71 - WebClient 72 - NativeApp 73 68 } 74 69 75 70 type User { ··· 362 357 None -> Nil 363 358 } 364 359 let client_type = case client_kind { 365 - "web" -> { 360 + WebClient -> { 366 361 connection_logger(woof.Debug, "A web client greets us!", []) 367 - WebClient 362 + client_kind 368 363 } 369 - _ -> todo 364 + webapi.NativeImplementation("android-reflector-" <> _) -> { 365 + connection_logger( 366 + woof.Debug, 367 + "A android client greets us!", 368 + [], 369 + ) 370 + client_kind 371 + } 372 + 373 + _ -> { 374 + connection_logger( 375 + woof.Debug, 376 + "A unknown native client greets us!", 377 + [], 378 + ) 379 + client_kind 380 + } 370 381 } 371 382 Some(ewe.websocket_continue( 372 383 WebsocketState(
+26 -25
web/src/lumina_client.gleam
··· 27 27 import gleam/string 28 28 import gleam/time/timestamp 29 29 import gleamy_lights/console 30 - import webapi.{encode_ws_msg_from_client as encode_ws_msg, LoginAuthenticationRequest, RegisterPrecheck, RegisterRequest, } 31 30 import gleamy_lights/premixed 32 31 import lumina_client/dom 33 32 import lumina_client/helpers.{login_view_checker, model_local_storage_key} ··· 47 46 import lustre/effect.{type Effect} 48 47 import lustre_websocket 49 48 import plinth/javascript/storage 49 + import webapi.{ 50 + LoginAuthenticationRequest, RegisterPrecheck, RegisterRequest, 51 + encode_ws_msg_from_client as encode_ws_msg, 52 + } 50 53 51 54 // HELPER FUNCTIONS ------------------------------------------------------------ 52 55 ··· 87 90 Ok(timeline) -> { 88 91 case homepage.get_next_page_to_load(timeline) { 89 92 Some(next_page) -> 90 - webapi.TimeLineRequest(timeline_name, next_page) 93 + webapi.TimeLineRequest(timeline_name, next_page) 91 94 |> encode_ws_msg 92 95 |> json.to_string 93 96 |> lustre_websocket.send(socket, _) ··· 95 98 } 96 99 } 97 100 Error(_) -> 98 - webapi.TimeLineRequest(timeline_name, 0) 101 + webapi.TimeLineRequest(timeline_name, 0) 99 102 |> encode_ws_msg 100 103 |> json.to_string 101 104 |> lustre_websocket.send(socket, _) ··· 510 513 // Request unless cached or load next page if needed. 511 514 let requ = case model.cache.cached_timelines |> dict.get(tid) { 512 515 Error(..) -> 513 - webapi.TimeLineRequest(tid, 0) 516 + webapi.TimeLineRequest(tid, 0) 514 517 |> encode_ws_msg 515 518 |> json.to_string 516 519 |> lustre_websocket.send(socket, _) ··· 520 523 True -> { 521 524 case homepage.get_next_page_to_load(timeline) { 522 525 Some(next_page) -> 523 - webapi.TimeLineRequest(tid, next_page) 526 + webapi.TimeLineRequest(tid, next_page) 524 527 |> encode_ws_msg 525 528 |> json.to_string 526 529 |> lustre_websocket.send(socket, _) ··· 591 594 case wsevent { 592 595 lustre_websocket.InvalidUrl -> panic 593 596 lustre_websocket.OnTextMessage(notice) -> 594 - case 595 - json.parse(notice, webapi.ws_msg_from_server_decoder()) 596 - { 597 - Ok(webapi.Greeting(m)) -> { 597 + case json.parse(notice, webapi.ws_msg_from_server_decoder()) { 598 + Ok(webapi.Greeting(m)) -> { 598 599 console.log("The server says hi! '" <> m <> "'") 599 600 #(model, effect.none()) 600 601 } 601 - Ok(webapi.RegisterPrecheckResponse(ok, why)) -> { 602 + Ok(webapi.RegisterPrecheckResponse(ok, why)) -> { 602 603 console.log("Register precheck response: " <> string.inspect(ok)) 603 604 let ready = 604 605 case ok { ··· 615 616 _ -> #(model, effect.none()) 616 617 } 617 618 } 618 - Ok(webapi.OwnUserInformationResponse( 619 + Ok(webapi.OwnUserInformationResponse( 619 620 username:, 620 621 email:, 621 622 avatar:, ··· 658 659 effect.none(), 659 660 ) 660 661 } 661 - Ok(webapi.AuthenticationSuccess(_username, token:)) -> { 662 + Ok(webapi.AuthenticationSuccess(_username, token:)) -> { 662 663 let assert model_type.WsConnectionConnected(socket) = model.ws 663 664 as "Socket not connected" 664 665 #( ··· 669 670 token: Some(token), 670 671 ), 671 672 effect.batch([ 672 - webapi.OwnUserInformationRequest 673 + webapi.OwnUserInformationRequest 673 674 |> encode_ws_msg 674 675 |> json.to_string 675 676 |> lustre_websocket.send(socket, _), 676 677 // Even though 'officially' we don't show the global timeline, this should be the one requested firstly. 677 - webapi.TimeLineRequest("global", 0) 678 + webapi.TimeLineRequest("global", 0) 678 679 |> encode_ws_msg 679 680 |> json.to_string 680 681 |> lustre_websocket.send(socket, _), 681 682 ]), 682 683 ) 683 684 } 684 - Ok(webapi.AuthenticationFailure) -> { 685 + Ok(webapi.AuthenticationFailure) -> { 685 686 case model.page { 686 687 model_type.Landing | HomeTimeline(..) | NotFound(..) | Licence -> 687 688 session_destroy() ··· 693 694 Register(..) -> #(model, effect.none()) 694 695 } 695 696 } 696 - Ok(webapi.TimeLineResponse( 697 + Ok(webapi.TimeLineResponse( 697 698 timeline_name:, 698 699 timeline_id:, 699 700 items:, ··· 722 723 let posts_fetches = 723 724 effect.batch( 724 725 list.map(items, fn(post_id) { 725 - webapi.PostContentRequest(post_id:) 726 + webapi.PostContentRequest(post_id:) 726 727 |> encode_ws_msg 727 728 |> json.to_string 728 729 |> lustre_websocket.send(socket, _) ··· 781 782 ) 782 783 #(model, effect.none()) 783 784 } 784 - Ok(webapi.Undecodable) -> 785 + Ok(webapi.Undecodable) -> 785 786 panic as "Received message that was explicitly marked as undecodable, this should not happen 786 787 as the decoder should have returned an error instead of Undecodable. Check the decoder implementation and the logs 787 788 for the raw message." ··· 833 834 Model(..model, ws: model_type.WsConnectionConnected(socket)), 834 835 lustre_websocket.send( 835 836 socket, 836 - webapi.Introduction("web", case model.user, model.token { 837 - None, Some(token) -> Some(token) 838 - _, _ -> None 839 - })|>encode_ws_msg|>json.to_string, 840 - 841 - ), 837 + webapi.Introduction(webapi.WebClient, case model.user, model.token { 838 + None, Some(token) -> Some(token) 839 + _, _ -> None 840 + }) 841 + |> encode_ws_msg 842 + |> json.to_string, 843 + ), 842 844 ) 843 845 } 844 846 } 845 - 846 847 847 848 fn send_refresh_request(model: model_type.Model) -> Effect(Msg) { 848 849 let current_time =