mirror of
https://github.com/onsonr/sonr.git
synced 2025-03-10 21:09:11 +00:00
- **refactor: move session-related code to middleware package** - **refactor: update PKL build process and adjust related configurations** - **feat: integrate base.cosmos.v1 Genesis module** - **refactor: pass session context to modal rendering functions** - **refactor: move nebula package to app directory and update templ version** - **refactor: Move home section video view to dedicated directory** - **refactor: remove unused views file** - **refactor: move styles and UI components to global scope** - **refactor: Rename images.go to cdn.go** - **feat: Add Empty State Illustrations** - **refactor: Consolidate Vault Index Logic** - **fix: References to App.wasm and remove Vault Directory embedded CDN files** - **refactor: Move CDN types to Models** - **fix: Correct line numbers in templ error messages for arch_templ.go** - **refactor: use common types for peer roles** - **refactor: move common types and ORM to a shared package** - **fix: Config import dwn** - **refactor: move nebula directory to app** - **feat: Rebuild nebula** - **fix: correct file paths in panels templates** - **feat: Remove duplicate types** - **refactor: Move dwn to pkg/core** - **refactor: Binary Structure** - **feat: Introduce Crypto Pkg** - **fix: Broken Process Start** - **feat: Update pkg/* structure** - **feat: Refactor PKL Structure** - **build: update pkl build process** - **chore: Remove Empty Files** - **refactor: remove unused macaroon package** - **feat: Add WebAwesome Components** - **refactor: consolidate build and generation tasks into a single taskfile, remove redundant makefile targets** - **refactor: refactor server and move components to pkg/core/dwn** - **build: update go modules** - **refactor: move gateway logic into dedicated hway command** - **feat: Add KSS (Krawczyk-Song-Song) MPC cryptography module** - **feat: Implement MPC-based JWT signing and UCAN token generation** - **feat: add support for MPC-based JWT signing** - **feat: Implement MPC-based UCAN capabilities for smart accounts** - **feat: add address field to keyshareSource** - **feat: Add comprehensive MPC test suite for keyshares, UCAN tokens, and token attenuations** - **refactor: improve MPC keyshare management and signing process** - **feat: enhance MPC capability hierarchy documentation** - **refactor: rename GenerateKeyshares function to NewKeyshareSource for clarity** - **refactor: remove unused Ethereum address computation** - **feat: Add HasHandle and IsAuthenticated methods to HTTPContext** - **refactor: Add context.Context support to session HTTPContext** - **refactor: Resolve context interface conflicts in HTTPContext** - **feat: Add session ID context key and helper functions** - **feat: Update WebApp Page Rendering** - **refactor: Simplify context management by using single HTTPContext key** - **refactor: Simplify HTTPContext creation and context management in session middleware** - **refactor: refactor session middleware to use a single data structure** - **refactor: Simplify HTTPContext implementation and session data handling** - **refactor: Improve session context handling and prevent nil pointer errors** - **refactor: Improve session context handling with nil safety and type support** - **refactor: improve session data injection** - **feat: add full-screen modal component and update registration flow** - **chore: add .air.toml to .gitignore** - **feat: add Air to devbox and update dependencies**
285 lines
7.5 KiB
Go
285 lines
7.5 KiB
Go
package handlers
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
"github.com/onsonr/sonr/pkg/core/dwn"
|
|
)
|
|
|
|
// generateRawServiceWorkerJS returns the service worker JavaScript as a string
|
|
func generateRawServiceWorkerJS(cfg *dwn.Environment) string {
|
|
return fmt.Sprintf(`const CACHE_NAMES = {
|
|
wasm: "wasm-cache-%s",
|
|
static: "static-cache-%s",
|
|
dynamic: "dynamic-cache-%s"
|
|
};
|
|
|
|
importScripts(
|
|
%q,
|
|
%q
|
|
);
|
|
|
|
// Initialize WASM HTTP listener with configured path
|
|
const wasmInstance = registerWasmHTTPListener(%q);
|
|
|
|
// MessageChannel port for WASM communication
|
|
let wasmPort;
|
|
|
|
// Request queue for offline operations
|
|
let requestQueue = new Map();
|
|
|
|
// Setup message channel handler
|
|
self.addEventListener('message', async (event) => {
|
|
if (event.data.type === 'PORT_INITIALIZATION') {
|
|
wasmPort = event.data.port;
|
|
setupWasmCommunication();
|
|
}
|
|
});
|
|
|
|
function setupWasmCommunication() {
|
|
wasmPort.onmessage = async (event) => {
|
|
const { type, data } = event.data;
|
|
|
|
switch (type) {
|
|
case 'WASM_REQUEST':
|
|
handleWasmRequest(data);
|
|
break;
|
|
case 'SYNC_REQUEST':
|
|
processSyncQueue();
|
|
break;
|
|
}
|
|
};
|
|
|
|
// Notify that WASM is ready
|
|
wasmPort.postMessage({ type: 'WASM_READY' });
|
|
}
|
|
|
|
// Enhanced install event
|
|
self.addEventListener("install", (event) => {
|
|
event.waitUntil(
|
|
Promise.all([
|
|
skipWaiting(),
|
|
// Cache WASM binary and essential resources
|
|
caches.open(CACHE_NAMES.wasm).then(cache =>
|
|
cache.addAll([
|
|
%q,
|
|
%q
|
|
])
|
|
)
|
|
])
|
|
);
|
|
});
|
|
|
|
// Enhanced activate event
|
|
self.addEventListener("activate", (event) => {
|
|
event.waitUntil(
|
|
Promise.all([
|
|
clients.claim(),
|
|
// Clean up old caches
|
|
caches.keys().then(keys =>
|
|
Promise.all(
|
|
keys.map(key => {
|
|
if (!Object.values(CACHE_NAMES).includes(key)) {
|
|
return caches.delete(key);
|
|
}
|
|
})
|
|
)
|
|
)
|
|
])
|
|
);
|
|
});
|
|
|
|
// Intercept fetch events
|
|
self.addEventListener('fetch', (event) => {
|
|
const request = event.request;
|
|
|
|
// Handle API requests differently from static resources
|
|
if (request.url.includes('/api/')) {
|
|
event.respondWith(handleApiRequest(request));
|
|
} else {
|
|
event.respondWith(handleStaticRequest(request));
|
|
}
|
|
});
|
|
|
|
async function handleApiRequest(request) {
|
|
try {
|
|
// Try to make the request
|
|
const response = await fetch(request.clone());
|
|
|
|
// If successful, pass through WASM handler
|
|
if (response.ok) {
|
|
return await processWasmResponse(request, response);
|
|
}
|
|
|
|
// If offline or failed, queue the request
|
|
await queueRequest(request);
|
|
|
|
// Return cached response if available
|
|
const cachedResponse = await caches.match(request);
|
|
if (cachedResponse) {
|
|
return cachedResponse;
|
|
}
|
|
|
|
// Return offline response
|
|
return new Response(
|
|
JSON.stringify({ error: 'Currently offline' }),
|
|
{
|
|
status: 503,
|
|
headers: { 'Content-Type': 'application/json' }
|
|
}
|
|
);
|
|
} catch (error) {
|
|
await queueRequest(request);
|
|
return new Response(
|
|
JSON.stringify({ error: 'Request failed' }),
|
|
{
|
|
status: 500,
|
|
headers: { 'Content-Type': 'application/json' }
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
async function handleStaticRequest(request) {
|
|
// Check cache first
|
|
const cachedResponse = await caches.match(request);
|
|
if (cachedResponse) {
|
|
return cachedResponse;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(request);
|
|
|
|
// Cache successful responses
|
|
if (response.ok) {
|
|
const cache = await caches.open(CACHE_NAMES.static);
|
|
cache.put(request, response.clone());
|
|
}
|
|
|
|
return response;
|
|
} catch (error) {
|
|
// Return offline page for navigation requests
|
|
if (request.mode === 'navigate') {
|
|
return caches.match('/offline.html');
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async function processWasmResponse(request, response) {
|
|
const responseClone = response.clone();
|
|
|
|
try {
|
|
const processedResponse = await wasmInstance.processResponse(responseClone);
|
|
|
|
if (wasmPort) {
|
|
wasmPort.postMessage({
|
|
type: 'RESPONSE',
|
|
requestId: request.headers.get('X-Wasm-Request-ID'),
|
|
response: processedResponse
|
|
});
|
|
}
|
|
|
|
return processedResponse;
|
|
} catch (error) {
|
|
console.error('WASM processing error:', error);
|
|
return response;
|
|
}
|
|
}
|
|
|
|
async function queueRequest(request) {
|
|
const serializedRequest = await serializeRequest(request);
|
|
requestQueue.set(request.url, serializedRequest);
|
|
|
|
try {
|
|
await self.registration.sync.register('wasm-sync');
|
|
} catch (error) {
|
|
console.error('Sync registration failed:', error);
|
|
}
|
|
}
|
|
|
|
async function serializeRequest(request) {
|
|
const headers = {};
|
|
for (const [key, value] of request.headers.entries()) {
|
|
headers[key] = value;
|
|
}
|
|
|
|
return {
|
|
url: request.url,
|
|
method: request.method,
|
|
headers,
|
|
body: await request.text(),
|
|
timestamp: Date.now()
|
|
};
|
|
}
|
|
|
|
// Handle background sync
|
|
self.addEventListener('sync', (event) => {
|
|
if (event.tag === 'wasm-sync') {
|
|
event.waitUntil(processSyncQueue());
|
|
}
|
|
});
|
|
|
|
async function processSyncQueue() {
|
|
const requests = Array.from(requestQueue.values());
|
|
|
|
for (const serializedRequest of requests) {
|
|
try {
|
|
const response = await fetch(new Request(serializedRequest.url, {
|
|
method: serializedRequest.method,
|
|
headers: serializedRequest.headers,
|
|
body: serializedRequest.body
|
|
}));
|
|
|
|
if (response.ok) {
|
|
requestQueue.delete(serializedRequest.url);
|
|
|
|
if (wasmPort) {
|
|
wasmPort.postMessage({
|
|
type: 'SYNC_COMPLETE',
|
|
url: serializedRequest.url
|
|
});
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Sync failed for request:', error);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle payment requests
|
|
self.addEventListener("canmakepayment", function (e) {
|
|
e.respondWith(Promise.resolve(true));
|
|
});
|
|
|
|
// Handle periodic sync if available
|
|
self.addEventListener('periodicsync', (event) => {
|
|
if (event.tag === 'wasm-sync') {
|
|
event.waitUntil(processSyncQueue());
|
|
}
|
|
});`,
|
|
cfg.CacheVersion,
|
|
cfg.CacheVersion,
|
|
cfg.CacheVersion,
|
|
cfg.WasmExecPath,
|
|
cfg.HttpserverPath,
|
|
cfg.WasmPath,
|
|
cfg.WasmPath,
|
|
cfg.WasmExecPath,
|
|
)
|
|
}
|
|
|
|
// ServiceWorkerHandler is an Echo handler that serves the service worker
|
|
func ServiceWorkerHandler(cfg *dwn.Environment) echo.HandlerFunc {
|
|
return func(c echo.Context) error {
|
|
// Set appropriate headers for service worker
|
|
c.Response().Header().Set("Content-Type", "application/javascript")
|
|
c.Response().Header().Set("Service-Worker-Allowed", "/")
|
|
|
|
// Generate and write the service worker JavaScript
|
|
return c.String(http.StatusOK, generateRawServiceWorkerJS(cfg))
|
|
}
|
|
}
|