Initial push
This commit is contained in:
145
hubzilla/addon/cry01/cry01_spool.php
Normal file
145
hubzilla/addon/cry01/cry01_spool.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* cry01_spool.php — POST handlers.
|
||||
* Validates input, builds spool envelope, POSTs to orchestrator.
|
||||
* Does not render HTML — returns rendered output from cry01_renderer.php.
|
||||
*/
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SIGNAL POST HANDLER
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function cry01_handle_signal_post($association_slug, $access) {
|
||||
// Validates and submits a capacity signal to the orchestrator spool receiver.
|
||||
$g1_pubkey = trim($_POST['g1_pubkey'] ?? '');
|
||||
$direction = trim($_POST['direction'] ?? '');
|
||||
$category_id = trim($_POST['category_id'] ?? '');
|
||||
$capacity_description = trim($_POST['capacity_description'] ?? '');
|
||||
$g1_denomination = trim($_POST['g1_denomination'] ?? '');
|
||||
$duration_days = intval($_POST['duration_days'] ?? 0);
|
||||
|
||||
// Validate required fields.
|
||||
$errors = [];
|
||||
if (!$g1_pubkey) $errors[] = 'Ğ1 public key is required.';
|
||||
if (!in_array($direction, ['offer', 'seek'])) $errors[] = 'Direction must be offer or seek.';
|
||||
if (!$category_id) $errors[] = 'Category is required.';
|
||||
if (!$capacity_description) $errors[] = 'Description is required.';
|
||||
if (!$g1_denomination || !is_numeric($g1_denomination) || floatval($g1_denomination) <= 0) {
|
||||
$errors[] = 'Ğ1 amount must be a positive number.';
|
||||
}
|
||||
if ($duration_days < 1 || $duration_days > 365) {
|
||||
$errors[] = 'Duration must be between 1 and 365 days.';
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
return '<div class="cry01-content"><div class="alert alert-danger"><ul class="mb-0">'
|
||||
. implode('', array_map(fn($e) => '<li>' . cry01_h($e) . '</li>', $errors))
|
||||
. '</ul></div></div>'
|
||||
. cry01_render_signal_form($association_slug, $access);
|
||||
}
|
||||
|
||||
$config = cry01_load_config();
|
||||
$token = $config['node_token'] ?? '';
|
||||
|
||||
// Build the spool envelope per contracts/signal-v1.json.
|
||||
$envelope = [
|
||||
'_header' => [
|
||||
'addon' => 'cry01',
|
||||
'association_slug' => $association_slug,
|
||||
'participant_xchan' => get_observer_hash(),
|
||||
'submitted_at' => date('c'),
|
||||
'node_token_hash' => hash('sha256', $token),
|
||||
],
|
||||
'_payload' => [
|
||||
'g1_pubkey' => $g1_pubkey,
|
||||
'capacity_description' => $capacity_description,
|
||||
'g1_denomination' => $g1_denomination,
|
||||
'duration_days' => $duration_days,
|
||||
'category_id' => $category_id,
|
||||
'direction' => $direction,
|
||||
],
|
||||
];
|
||||
|
||||
$result = cry01_post_to_orchestrator('/cry01/signal', $envelope);
|
||||
|
||||
if ($result === true) {
|
||||
return '<div class="cry01-content">'
|
||||
. '<div class="alert alert-success">Signal registered successfully. '
|
||||
. 'A Verifiable Credential will be issued and timestamped to Bitcoin.</div>'
|
||||
. '<p><a href="' . z_root() . '/cry01/' . cry01_h($association_slug) . '">← Back to Value Layer</a></p>'
|
||||
. '</div>';
|
||||
}
|
||||
|
||||
return '<div class="cry01-content">'
|
||||
. '<div class="alert alert-danger">Signal could not be registered. '
|
||||
. 'The orchestrator may be temporarily unavailable. Please try again.</div>'
|
||||
. '</div>'
|
||||
. cry01_render_signal_form($association_slug, $access);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// MANAGE POST HANDLER
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function cry01_handle_manage_post($association_slug) {
|
||||
// Handles operator manage actions: currently only cache refresh.
|
||||
if (!cry01_verify_csrf()) {
|
||||
return cry01_render_error('Invalid form token. Please reload and try again.');
|
||||
}
|
||||
|
||||
$action = $_POST['action'] ?? '';
|
||||
|
||||
if ($action === 'refresh_cache') {
|
||||
$ok = cry01_refresh_balance_cache();
|
||||
$msg = $ok
|
||||
? '<div class="alert alert-success">Balance cache refreshed successfully.</div>'
|
||||
: '<div class="alert alert-warning">Cache refresh failed. Check that the Duniter node is reachable and the operator Ğ1 key is configured.</div>';
|
||||
return '<div class="cry01-content">' . $msg . '</div>' . cry01_render_manage($association_slug);
|
||||
}
|
||||
|
||||
return cry01_render_error('Unknown action.');
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ORCHESTRATOR TRANSPORT
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function cry01_post_to_orchestrator($path, $payload) {
|
||||
// POSTs a JSON envelope to the orchestrator spool receiver.
|
||||
// Returns true on success (HTTP 201), false on any failure.
|
||||
$config = cry01_load_config();
|
||||
$base = rtrim($config['receiver_url'] ?? '', '/');
|
||||
if (!$base) {
|
||||
logger('cry01_spool: receiver_url not configured');
|
||||
return false;
|
||||
}
|
||||
|
||||
$url = $base . $path;
|
||||
$body = json_encode($payload);
|
||||
|
||||
$context = stream_context_create([
|
||||
'http' => [
|
||||
'method' => 'POST',
|
||||
'header' => "Content-Type: application/json\r\nContent-Length: " . strlen($body) . "\r\n",
|
||||
'content' => $body,
|
||||
'timeout' => 10,
|
||||
'ignore_errors' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$raw = @file_get_contents($url, false, $context);
|
||||
$headers = $http_response_header ?? [];
|
||||
$status = 0;
|
||||
|
||||
foreach ($headers as $h) {
|
||||
if (preg_match('/HTTP\/\d\.\d\s+(\d+)/', $h, $m)) {
|
||||
$status = intval($m[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($status === 201) return true;
|
||||
|
||||
logger('cry01_spool: orchestrator returned status ' . $status . ' for ' . $path);
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user