mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-12-29 03:21:33 +03:00
commit
22700f4e97
@ -88,7 +88,6 @@ fn make_widget() -> String {
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#latest-apps {
|
||||
|
@ -163,6 +163,8 @@ fn init(our: Address) {
|
||||
.bind_http_path("/order", http_config)
|
||||
.expect("failed to bind /order");
|
||||
|
||||
kinode_process_lib::homepage::add_to_homepage("Clock", None, None, Some(&make_clock_widget()));
|
||||
|
||||
// load persisted app order
|
||||
let mut persisted_app_order =
|
||||
kinode_process_lib::get_typed_state(|bytes| serde_json::from_slice(bytes))
|
||||
@ -194,7 +196,12 @@ fn init(our: Address) {
|
||||
)),
|
||||
),
|
||||
"/version" => {
|
||||
if app_data.len() >= 4 {
|
||||
// hacky way to ensure that the homepage has populated itself before
|
||||
// loading in after boot
|
||||
if app_data.len() >= 4
|
||||
&& app_data.values().filter(|app| app.widget.is_some()).count()
|
||||
>= 3
|
||||
{
|
||||
(
|
||||
server::HttpResponse::new(http::StatusCode::OK),
|
||||
Some(LazyLoadBlob::new(
|
||||
@ -381,3 +388,126 @@ fn version_from_cargo_toml() -> String {
|
||||
.trim_matches('"')
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn make_clock_widget() -> String {
|
||||
return format!(
|
||||
r#"<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/kinode.css">
|
||||
<style>
|
||||
.clock {{
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 8px solid var(--text);
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
margin: 20px auto;
|
||||
}}
|
||||
.hand {{
|
||||
position: absolute;
|
||||
bottom: 50%;
|
||||
left: 50%;
|
||||
transform-origin: bottom;
|
||||
background-color: light-dark(var(--off-black), var(--off-white));
|
||||
}}
|
||||
.hour {{
|
||||
width: 4px;
|
||||
height: 60px;
|
||||
margin-left: -2px;
|
||||
}}
|
||||
.minute {{
|
||||
width: 3px;
|
||||
height: 80px;
|
||||
margin-left: -1.5px;
|
||||
}}
|
||||
.second {{
|
||||
width: 2px;
|
||||
height: 90px;
|
||||
margin-left: -1px;
|
||||
background-color: var(--orange);
|
||||
}}
|
||||
.center {{
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}}
|
||||
.marker {{
|
||||
position: absolute;
|
||||
width: 2px;
|
||||
height: 4px;
|
||||
background: light-dark(var(--off-black), var(--off-white));
|
||||
left: 50%;
|
||||
margin-left: -1px;
|
||||
transform-origin: 50% 100px;
|
||||
}}
|
||||
.marker.primary {{
|
||||
width: 3px;
|
||||
height: 8px;
|
||||
margin-left: -1.5px;
|
||||
}}
|
||||
.digital-time {{
|
||||
font-family: var(--font-family-main);
|
||||
margin-top: 1em;
|
||||
font-size: 0.7em;
|
||||
color: light-dark(var(--off-black), var(--off-white));
|
||||
position: absolute;
|
||||
width:100%;
|
||||
text-align: center;
|
||||
bottom: 40px;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body style="margin: 0;">
|
||||
<div class="clock">
|
||||
<div class="marker primary" style="transform: rotate(0deg)"></div>
|
||||
<div class="marker" style="transform: rotate(30deg)"></div>
|
||||
<div class="marker" style="transform: rotate(60deg)"></div>
|
||||
<div class="marker primary" style="transform: rotate(90deg)"></div>
|
||||
<div class="marker" style="transform: rotate(120deg)"></div>
|
||||
<div class="marker" style="transform: rotate(150deg)"></div>
|
||||
<div class="marker primary" style="transform: rotate(180deg)"></div>
|
||||
<div class="marker" style="transform: rotate(210deg)"></div>
|
||||
<div class="marker" style="transform: rotate(240deg)"></div>
|
||||
<div class="marker primary" style="transform: rotate(270deg)"></div>
|
||||
<div class="marker" style="transform: rotate(300deg)"></div>
|
||||
<div class="marker" style="transform: rotate(330deg)"></div>
|
||||
<div class="hand hour" id="hour"></div>
|
||||
<div class="hand minute" id="minute"></div>
|
||||
<div class="hand second" id="second"></div>
|
||||
<div class="center"></div>
|
||||
</div>
|
||||
<div class="digital-time" id="digital"></div>
|
||||
|
||||
<script>
|
||||
function updateClock() {{
|
||||
const now = new Date();
|
||||
const hours = now.getHours() % 12;
|
||||
const minutes = now.getMinutes();
|
||||
const seconds = now.getSeconds();
|
||||
|
||||
const hourDeg = (hours * 30) + (minutes * 0.5);
|
||||
const minuteDeg = minutes * 6;
|
||||
const secondDeg = seconds * 6;
|
||||
|
||||
document.getElementById('hour').style.transform = `rotate(${{hourDeg}}deg)`;
|
||||
document.getElementById('minute').style.transform = `rotate(${{minuteDeg}}deg)`;
|
||||
document.getElementById('second').style.transform = `rotate(${{secondDeg}}deg)`;
|
||||
|
||||
// Update digital display
|
||||
const displayHours = hours === 0 ? 12 : hours;
|
||||
const displayMinutes = minutes.toString().padStart(2, '0');
|
||||
document.getElementById('digital').textContent = `${{displayHours}}:${{displayMinutes}}`;
|
||||
}}
|
||||
|
||||
setInterval(updateClock, 1000);
|
||||
updateClock();
|
||||
</script>
|
||||
</body>
|
||||
</html>"#
|
||||
);
|
||||
}
|
||||
|
@ -109,15 +109,11 @@ impl State {
|
||||
impl From<net::KnsUpdate> for WitKnsUpdate {
|
||||
fn from(k: net::KnsUpdate) -> Self {
|
||||
WitKnsUpdate {
|
||||
name: k.name.clone(),
|
||||
public_key: k.public_key.clone(),
|
||||
ips: k.ips.clone(),
|
||||
ports: k
|
||||
.ports
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.clone()))
|
||||
.collect::<Vec<_>>(),
|
||||
routers: k.routers.clone(),
|
||||
name: k.name,
|
||||
public_key: k.public_key,
|
||||
ips: k.ips,
|
||||
ports: k.ports.into_iter().map(|(k, v)| (k, v)).collect::<Vec<_>>(),
|
||||
routers: k.routers,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,11 +121,11 @@ impl From<net::KnsUpdate> for WitKnsUpdate {
|
||||
impl From<WitKnsUpdate> for net::KnsUpdate {
|
||||
fn from(k: WitKnsUpdate) -> Self {
|
||||
net::KnsUpdate {
|
||||
name: k.name.clone(),
|
||||
public_key: k.public_key.clone(),
|
||||
ips: k.ips.clone(),
|
||||
name: k.name,
|
||||
public_key: k.public_key,
|
||||
ips: k.ips,
|
||||
ports: BTreeMap::from_iter(k.ports),
|
||||
routers: k.routers.clone(),
|
||||
routers: k.routers,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -138,19 +134,15 @@ impl From<State> for WitState {
|
||||
fn from(s: State) -> Self {
|
||||
let contract_address: [u8; 20] = s.contract_address.into();
|
||||
WitState {
|
||||
chain_id: s.chain_id.clone(),
|
||||
chain_id: s.chain_id,
|
||||
contract_address: contract_address.to_vec(),
|
||||
names: s
|
||||
.names
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.clone()))
|
||||
.collect::<Vec<_>>(),
|
||||
names: s.names.into_iter().map(|(k, v)| (k, v)).collect::<Vec<_>>(),
|
||||
nodes: s
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.clone().into()))
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, v.into()))
|
||||
.collect::<Vec<_>>(),
|
||||
last_block: s.last_checkpoint_block.clone(),
|
||||
last_block: s.last_checkpoint_block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -369,6 +369,14 @@ async fn handle_kernel_request(
|
||||
.expect("event loop: fatal: sender died");
|
||||
None
|
||||
}
|
||||
t::KernelCommand::SetOnExit { target, on_exit } => {
|
||||
if let Some(process) = process_map.get_mut(&target) {
|
||||
process.on_exit = on_exit;
|
||||
}
|
||||
// persist state because it changed
|
||||
persist_state(&send_to_loop, process_map).await;
|
||||
None
|
||||
}
|
||||
//
|
||||
// send 'run' message to a process that's already been initialized
|
||||
//
|
||||
|
@ -497,11 +497,42 @@ impl StandardHost for process::ProcessWasiV1 {
|
||||
// process management:
|
||||
//
|
||||
|
||||
/// TODO critical: move to kernel logic to enable persistence of choice made here
|
||||
async fn set_on_exit(&mut self, on_exit: wit::OnExit) -> Result<()> {
|
||||
self.process.metadata.on_exit = t::OnExit::de_wit_v1(on_exit);
|
||||
print_debug(&self.process, "set new on-exit behavior").await;
|
||||
Ok(())
|
||||
let on_exit = t::OnExit::de_wit_v1(on_exit);
|
||||
self.process.metadata.on_exit = on_exit.clone();
|
||||
match self
|
||||
.process
|
||||
.send_request_v1(
|
||||
Some(t::Address {
|
||||
node: self.process.metadata.our.node.clone(),
|
||||
process: KERNEL_PROCESS_ID.clone(),
|
||||
}),
|
||||
wit::Address {
|
||||
node: self.process.metadata.our.node.clone(),
|
||||
process: KERNEL_PROCESS_ID.en_wit_v1(),
|
||||
},
|
||||
wit::Request {
|
||||
inherit: false,
|
||||
expects_response: None,
|
||||
body: serde_json::to_vec(&t::KernelCommand::SetOnExit {
|
||||
target: self.process.metadata.our.process.clone(),
|
||||
on_exit,
|
||||
})
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
capabilities: vec![],
|
||||
},
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
print_debug(&self.process, "set new on-exit behavior").await;
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_on_exit(&mut self) -> Result<wit::OnExit> {
|
||||
|
@ -75,10 +75,7 @@ pub async fn load_state(
|
||||
}
|
||||
}
|
||||
|
||||
// bootstrap the distro processes into the node. TODO:
|
||||
// once we manage userspace sys packages onchain, stop
|
||||
// doing this and allow node operator to manually or auto-update
|
||||
// all their own userspace packages.
|
||||
// bootstrap the distro processes into the node
|
||||
bootstrap(
|
||||
&our_name,
|
||||
keypair,
|
||||
|
@ -429,6 +429,8 @@ pub enum KernelCommand {
|
||||
target: ProcessId,
|
||||
capabilities: Vec<Capability>,
|
||||
},
|
||||
/// Set the on-exit behavior for a process.
|
||||
SetOnExit { target: ProcessId, on_exit: OnExit },
|
||||
/// Tell the kernel to run a process that has already been installed.
|
||||
/// TODO: in the future, this command could be extended to allow for
|
||||
/// resource provision.
|
||||
|
Loading…
Reference in New Issue
Block a user