websocket and browser source, quick and dirty implementation of the statusline

This commit is contained in:
Jeeves 2025-02-17 08:22:40 -07:00
parent 6ce0d30b4c
commit b419eeb1c4
8 changed files with 207 additions and 23 deletions

View file

@ -7,5 +7,6 @@
"build.zig",
"build.zig.zon",
"src",
"public",
},
}

6
flake.lock generated
View file

@ -59,11 +59,11 @@
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1739496552,
"narHash": "sha256-if34rjhH/CXZQTnAl629tVdz/mAx/fifjTPRPQsJ1tg=",
"lastModified": 1739670160,
"narHash": "sha256-9QI3sDNp+Pmr7mcaeabqXrADaF8SAZ98LnB/I23FnXs=",
"owner": "Cloudef",
"repo": "zig2nix",
"rev": "0dae566efe9a0ed18c07b76a5ed8ff2c546bdd56",
"rev": "3dae27fb3c702b7f28425518e914b0ab34575ff5",
"type": "github"
},
"original": {

View file

@ -14,6 +14,12 @@ const std = @import("std");
//
// A - means immediately, a + means eventually.
var global_connection: ?std.net.Server.Connection = null;
var global_websocket: ?*std.http.WebSocket = null;
var global_send_buf: ?[]u8 = null;
var global_recv_buf: ?[]align(4) u8 = null;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
@ -27,10 +33,82 @@ pub fn main() !void {
var tz = try std.tz.Tz.parse(allocator, tz_file.reader());
defer tz.deinit();
while (true) : (std.time.sleep(1_000_000_000)) { // sleep 500ms
try updateTime(tz);
try updateStatus(allocator, &vlc);
scroll += 1;
var server = try std.net.Address.initIp4(.{ 127, 0, 0, 1 }, 8009).listen(.{});
defer server.deinit();
// while (true) : (std.time.sleep(1_000_000_000)) { // sleep 500ms
// try updateTime(tz);
// try updateStatus(allocator, &vlc);
// // scroll += 1;
// }
defer if (global_connection) |conn| conn.stream.close();
defer if (global_send_buf) |buf| allocator.free(buf);
defer if (global_recv_buf) |buf| allocator.free(buf);
var delay: u8 = 0;
while (true) {
var pollfds = [_]std.posix.pollfd{.{ .fd = server.stream.handle, .events = std.posix.POLL.IN, .revents = 0 }};
const num = try std.posix.poll(&pollfds, 100);
std.debug.print("num pollfds {d}\nrevents {d}\n", .{ num, pollfds[0].revents });
if (pollfds[0].revents != 0) {
const read_buf = try allocator.alloc(u8, 1024 * 32);
defer allocator.free(read_buf);
const connection = try server.accept();
errdefer connection.stream.close();
var http = std.http.Server.init(connection, read_buf);
var request = try http.receiveHead();
std.debug.print("Target: {s}\n", .{request.head.target});
var websocket: std.http.WebSocket = undefined;
global_send_buf = try allocator.alloc(u8, 1024 * 32);
global_recv_buf = try allocator.alignedAlloc(u8, 4, 1024 * 32);
const is_websocket = try websocket.init(&request, global_send_buf.?, global_recv_buf.?);
if (is_websocket) {
try websocket.response.flush();
std.debug.print("is a websocket now\n", .{});
global_connection = connection;
global_websocket = &websocket;
// const msg = try websocket.readSmallMessage();
// std.debug.print("{any}\n{s}\n", .{ msg, msg.data });
// try websocket.writeMessage("dude i cant believe you just ate that", .text);
// // try websocket.writeMessage("", .ping);
// std.time.sleep(5_000_000_000);
// try websocket.writeMessage("dude why did i just eat that now", .text);
// std.debug.print("sent second one\n", .{});
} else {
defer connection.stream.close();
switch (request.head.method) {
.GET, .HEAD => {
if (std.mem.eql(u8, request.head.target, "/gone")) {
try request.respond(@embedFile("web/gone.html"), .{});
} else if (std.mem.eql(u8, request.head.target, "/statusline")) {
try request.respond(@embedFile("web/statusline.html"), .{});
} else if (std.mem.eql(u8, request.head.target, "/gone.js")) {
try request.respond(@embedFile("web/gone.js"), .{});
} else if (std.mem.eql(u8, request.head.target, "/statusline.js")) {
try request.respond(@embedFile("web/statusline.js"), .{});
} else if (std.mem.eql(u8, request.head.target, "/style.css")) {
try request.respond(@embedFile("web/style.css"), .{});
} else {
try request.respond("", .{ .status = .not_found });
}
},
else => try request.respond("", .{ .status = .not_found }),
}
}
}
delay += 1;
if (delay == 10) {
delay = 0;
try updateStatus(allocator, &vlc);
}
}
}
@ -39,27 +117,30 @@ const base64_encoder = std.base64.standard.Encoder;
// TODO make the URL something short like jeevio.xyz/streamboy
const topic = "Something Fun For Everyone With Streamboy!!!!!!!! git.jeevio.xyz/jeeves/streamboy";
var scroll: usize = 0;
// var scroll: usize = 0;
fn updateStatus(allocator: std.mem.Allocator, vlc: *VLC) !void {
var stream_info_file = try std.fs.createFileAbsolute("/tmp/streaminfo", .{ .truncate = true });
defer stream_info_file.close();
// var stream_info_file = try std.fs.createFileAbsolute("/tmp/streaminfo", .{ .truncate = true });
// defer stream_info_file.close();
if (global_websocket) |ws| {
var song_info = try vlc.getSongInfo();
defer song_info.deinit();
var song_info = try vlc.getSongInfo();
defer song_info.deinit();
const string = try std.fmt.allocPrint(allocator, "{s} | ♪ {s} - {s} | ", .{
topic,
song_info.title orelse "Unknown Title",
song_info.artist orelse "Unknown Artist",
});
defer allocator.free(string);
const string = try std.fmt.allocPrint(allocator, "{s} | ♪ {s} - {s} | ", .{
topic,
song_info.title orelse "Unknown Title",
song_info.artist orelse "Unknown Artist",
});
defer allocator.free(string);
if (scroll > string.len) scroll = 0;
if (scroll == 0) try stream_info_file.writeAll(string) else {
for (string[scroll..]) |char| try stream_info_file.writer().writeByte(char);
for (string[0..scroll]) |char| try stream_info_file.writer().writeByte(char);
try ws.writeMessage(string, .text);
}
// if (scroll > string.len) scroll = 0;
// if (scroll == 0) try stream_info_file.writeAll(string) else {
// for (string[scroll..]) |char| try stream_info_file.writer().writeByte(char);
// for (string[0..scroll]) |char| try stream_info_file.writer().writeByte(char);
// }
}
pub const VLC = struct {

13
src/web/gone.html Normal file
View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="style.css" />
<!-- <script type="text/javascript" src="https://livejs.com/live.js"></script> -->
</head>
<body>
<p id="gone">[gone]</p>
<p id="date"></p>
<script src="gone.js"></script>
</body>

49
src/web/gone.js Normal file
View file

@ -0,0 +1,49 @@
// Sunday, February 16 2025, 03:06:20 PM
const dateElement = document.getElementById("date");
const months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
const daysOfWeek = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
function updateDateTime() {
const date = new Date();
const seconds = date.getSeconds();
const minutes = date.getMinutes();
const hours24 = date.getHours();
const hours12 = hours24 % 12;
const ampm = hours24 > 11 && hours24 != 0 ? "PM" : "AM";
const secondsString = String(seconds).padStart(2, "0");
const minutesString = String(minutes).padStart(2, "0");
const year = date.getFullYear();
const month = months[date.getMonth()];
const day = date.getDate();
const dayOfWeek = daysOfWeek[date.getDay()];
dateElement.innerText = `${dayOfWeek}, ${month} ${day} ${year}, ${hours12}:${minutesString}:${secondsString} ${ampm}`;
}
setInterval(updateDateTime, 1000);

12
src/web/statusline.html Normal file
View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="style.css" />
<!-- <script type="text/javascript" src="https://livejs.com/live.js"></script> -->
</head>
<body>
<p id="status-line"></p>
<script src="statusline.js"></script>
</body>

12
src/web/statusline.js Normal file
View file

@ -0,0 +1,12 @@
const statusLineElement = document.getElementById("status-line");
const socket = new WebSocket("ws://localhost:8009");
// socket.addEventListener("open", (event) => {
// socket.send("Hello Server!");
// });
socket.addEventListener("message", (event) => {
console.log("Message from server ", event.data);
statusLineElement.textContent = event.data;
});

16
src/web/style.css Normal file
View file

@ -0,0 +1,16 @@
body {
font-family: Unifont;
background-color: black;
color: white;
margin: 0px auto;
overflow: hidden;
}
#gone {
font-size: 64px;
}
#status-line {
font-size: 16px;
margin: 0px;
}