Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions kinode/packages/homepage/api/homepage:sys-v0.wit
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ interface homepage {
/// the icon is a base64 encoded image.
add(add-request),
remove,
/// ONLY settings:settings:sys may call this request
/// (this is checked in-code)
set-stylesheet(string),
}

record add-request {
Expand Down
57 changes: 52 additions & 5 deletions kinode/packages/homepage/homepage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,43 @@ fn init(our: Address) {
)
.expect("failed to bind to /our.js");

// the base version gets written over on-bootstrap, so we look for
// the persisted (user-customized) version first.
// if it doesn't exist, we use the bootstrapped version and save it here.
let stylesheet = kinode_process_lib::vfs::File {
path: "/homepage:sys/pkg/persisted-kinode.css".to_string(),
timeout: 5,
}
.read()
.unwrap_or_else(|_| {
kinode_process_lib::vfs::File {
path: "/homepage:sys/pkg/kinode.css".to_string(),
timeout: 5,
}
.read()
.expect("failed to get kinode.css")
});

// save the stylesheet to the persisted file
kinode_process_lib::vfs::File {
path: "/homepage:sys/pkg/persisted-kinode.css".to_string(),
timeout: 5,
}
.write(&stylesheet)
.expect("failed to write to /persisted-kinode.css");

bind_http_static_path(
"/kinode.css",
true,
false, // kinode.css is not auth'd so that apps on subdomains can use it too!
false,
Some("text/css".to_string()),
include_str!("../../pkg/kinode.css").into(),
stylesheet,
)
.expect("failed to bind /kinode.css");

bind_http_static_path(
"/kinode.svg",
true,
false, // kinode.svg is not auth'd so that apps on subdomains can use it too!
false,
Some("image/svg+xml".to_string()),
include_str!("../../pkg/kinode.svg").into(),
Expand All @@ -94,7 +119,7 @@ fn init(our: Address) {

bind_http_static_path(
"/bird-orange.svg",
true,
false, // bird-orange.svg is not auth'd so that apps on subdomains can use it too!
false,
Some("image/svg+xml".to_string()),
include_str!("../../pkg/bird-orange.svg").into(),
Expand All @@ -103,7 +128,7 @@ fn init(our: Address) {

bind_http_static_path(
"/bird-plain.svg",
true,
false, // bird-plain.svg is not auth'd so that apps on subdomains can use it too!
false,
Some("image/svg+xml".to_string()),
include_str!("../../pkg/bird-plain.svg").into(),
Expand Down Expand Up @@ -173,6 +198,28 @@ fn init(our: Address) {
HomepageRequest::Remove => {
app_data.remove(&message.source().process.to_string());
}
HomepageRequest::SetStylesheet(new_stylesheet_string) => {
// ONLY settings:settings:sys may call this request
if message.source().process != "settings:settings:sys" {
continue;
}
kinode_process_lib::vfs::File {
path: "/homepage:sys/pkg/persisted-kinode.css".to_string(),
timeout: 5,
}
.write(new_stylesheet_string.as_bytes())
.expect("failed to write to /persisted-kinode.css");
// re-bind
bind_http_static_path(
"/kinode.css",
false, // kinode.css is not auth'd so that apps on subdomains can use it too!
false,
Some("text/css".to_string()),
new_stylesheet_string.into(),
)
.expect("failed to bind /kinode.css");
println!("updated kinode.css!");
}
}
} else if let Ok(req) = serde_json::from_slice::<HttpServerRequest>(message.body()) {
match req {
Expand Down
8 changes: 7 additions & 1 deletion kinode/packages/settings/pkg/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@
"http_server:distro:sys",
"kernel:distro:sys",
"net:distro:sys",
"vfs:distro:sys"
"vfs:distro:sys",
{
"process": "vfs:distro:sys",
"params": {
"root": true
}
}
],
"grant_capabilities": [
"eth:distro:sys",
Expand Down
33 changes: 29 additions & 4 deletions kinode/packages/settings/pkg/ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,22 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="/kinode.css">
<link href="https://fonts.googleapis.com/css2?family=Kode+Mono:wght@700&display=swap" rel="stylesheet">
<script src="/our.js"></script>
<script>
document.title = window.our.node + " - settings";
</script>
<style>
body {
font-family: 'Courier New', Courier, monospace;
color: #f0f0f0;
h1,
h2,
h3,
h4,
h5,
h6,
p,
a,
li {
font-family: 'Kode Mono', monospace;
}

h1 {
Expand All @@ -33,7 +41,8 @@
"diagnostics diagnostics diagnostics"
"node-info pings pings"
"eth-rpc-providers eth-rpc-providers eth-rpc-settings"
"kernel kernel kernel";
"kernel kernel kernel"
"kinode-css kinode-css kinode-css";
padding: 20px;
max-width: 960px;
min-width: 300px;
Expand Down Expand Up @@ -80,6 +89,16 @@
grid-area: kernel;
}

article#kinode-css {
grid-area: kinode-css;
}

textarea#stylesheet-editor {
width: 100%;
min-width: 300px;
min-height: 400px;
}

div#provider-edits {
display: grid;
grid-template-columns: 1fr 1fr;
Expand Down Expand Up @@ -200,6 +219,12 @@ <h2>running processes</h2>
<ul id="process-map"></ul>
</article>

<article id="kinode-css">
<h2>stylesheet editor</h2>
<textarea id="stylesheet-editor"></textarea>
<button id="save-stylesheet">update kinode.css</button>
</article>


<script src="/settings:settings:sys/script.js"></script>
</main>
Expand Down
13 changes: 12 additions & 1 deletion kinode/packages/settings/pkg/ui/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ function init() {
fetch(APP_PATH)
.then(response => response.json())
.then(data => {
console.log(data);
populate(data);
});
}
Expand Down Expand Up @@ -33,6 +32,7 @@ function populate(data) {
populate_eth_rpc_providers(data.eth_rpc_providers);
populate_eth_rpc_settings(data.eth_rpc_access_settings);
populate_process_map(data.process_map);
populate_stylesheet_editor(data.stylesheet);
}

function populate_node_info(identity) {
Expand Down Expand Up @@ -180,12 +180,23 @@ function populate_process_map(process_map) {
});
}

function populate_stylesheet_editor(stylesheet) {
document.getElementById('stylesheet-editor').value = stylesheet;
}

function save_stylesheet() {
const stylesheet = document.getElementById('stylesheet-editor').value;
api_call({ "SetStylesheet": stylesheet });
}

// Call init to start the application
init();

// Setup event listeners
document.getElementById('shutdown').addEventListener('click', shutdown);

document.getElementById('save-stylesheet').addEventListener('click', save_stylesheet);

document.getElementById('get-peer-pki').addEventListener('submit', (e) => {
e.preventDefault();
const data = new FormData(e.target);
Expand Down
61 changes: 42 additions & 19 deletions kinode/packages/settings/settings/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use kinode_process_lib::{println, *};
use kinode_process_lib::{
await_message, call_init, eth, get_blob, homepage, http, kernel_types, net, println, Address,
LazyLoadBlob, Message, NodeId, ProcessId, Request, Response, SendError, SendErrorKind,
};
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
extern crate base64;
Expand All @@ -16,6 +19,7 @@ enum SettingsRequest {
EthConfig(eth::EthConfigAction),
Shutdown,
KillProcess(ProcessId),
SetStylesheet(String),
}

type SettingsResponse = Result<Option<SettingsData>, SettingsError>;
Expand Down Expand Up @@ -44,6 +48,7 @@ struct SettingsState {
pub eth_rpc_providers: Option<eth::SavedConfigs>,
pub eth_rpc_access_settings: Option<eth::AccessSettings>,
pub process_map: Option<kernel_types::ProcessMap>,
pub stylesheet: Option<String>,
}

impl SettingsState {
Expand All @@ -56,6 +61,7 @@ impl SettingsState {
eth_rpc_providers: None,
eth_rpc_access_settings: None,
process_map: None,
stylesheet: None,
}
}

Expand Down Expand Up @@ -152,6 +158,16 @@ impl SettingsState {
};
self.process_map = Some(process_map);

// stylesheet
if let Ok(bytes) = (kinode_process_lib::vfs::File {
path: "/homepage:sys/pkg/kinode.css".to_string(),
timeout: 5,
}
.read())
{
self.stylesheet = Some(String::from_utf8_lossy(&bytes).to_string());
}

Ok(())
}
}
Expand All @@ -164,26 +180,13 @@ wit_bindgen::generate!({
call_init!(initialize);
fn initialize(our: Address) {
// add ourselves to the homepage
Request::to(("our", "homepage", "homepage", "sys"))
.body(
serde_json::json!({
"Add": {
"label": "Settings",
"icon": ICON,
"path": "/", // just our root
}
})
.to_string()
.as_bytes()
.to_vec(),
)
.send()
.unwrap();
homepage::add_to_homepage("Settings", Some(ICON), Some("/"), None);

// Serve the index.html and other UI files found in pkg/ui at the root path.
http::serve_ui(&our, "ui", true, false, vec!["/"]).unwrap();
http::bind_http_path("/ask", true, false).unwrap();
http::bind_ws_path("/", true, false).unwrap();
// Serving securely at `settings-sys` subdomain
http::secure_serve_ui(&our, "ui", vec!["/"]).unwrap();
http::secure_bind_http_path("/ask").unwrap();
http::secure_bind_ws_path("/", false).unwrap();

// Grab our state, then enter the main event loop.
let mut state: SettingsState = SettingsState::new(our);
Expand Down Expand Up @@ -401,6 +404,26 @@ fn handle_settings_request(
return SettingsResponse::Err(SettingsError::KernelNonresponsive);
}
}
SettingsRequest::SetStylesheet(stylesheet) => {
let Ok(()) = kinode_process_lib::vfs::File {
path: "/homepage:sys/pkg/kinode.css".to_string(),
timeout: 5,
}
.write(stylesheet.as_bytes()) else {
return SettingsResponse::Err(SettingsError::KernelNonresponsive);
};
Request::to(("our", "homepage", "homepage", "sys"))
.body(
serde_json::json!({ "SetStylesheet": stylesheet })
.to_string()
.as_bytes(),
)
.send()
.unwrap();
state.stylesheet = Some(stylesheet);
state.ws_update();
return SettingsResponse::Ok(None);
}
}

state.fetch().map_err(|_| SettingsError::StateFetchFailed)?;
Expand Down
Loading