174 lines
4.3 KiB
JavaScript
174 lines
4.3 KiB
JavaScript
/**
|
|
* PearData P2P protocol — control plane + metric streaming.
|
|
*
|
|
* PROTOCOL_VERSION is negotiated via `handshake`. Bump on breaking RPC shapes.
|
|
* Additive methods may land without a bump when clients tolerate unknown methods.
|
|
*
|
|
* Planes:
|
|
* - Control/metadata: handshake, info, ACL, invites, jobs, alerts config
|
|
* - Metrics query: contexts, charts, historical data (hot path)
|
|
* - Push streams: live samples, anomalies, health events
|
|
*/
|
|
|
|
export const PROTOCOL = 'peardata/rpc'
|
|
export const PROTOCOL_VERSION = 1
|
|
export const APP_NAME = 'peardata'
|
|
export const APP_VERSION = '0.1.0'
|
|
|
|
/** Roles for capability ACL. Secure default peer role is viewer. */
|
|
export const Roles = Object.freeze({
|
|
viewer: 'viewer',
|
|
operator: 'operator',
|
|
admin: 'admin',
|
|
})
|
|
|
|
const ROLE_RANK = {
|
|
[Roles.viewer]: 1,
|
|
[Roles.operator]: 2,
|
|
[Roles.admin]: 3,
|
|
}
|
|
|
|
/**
|
|
* @param {string} role
|
|
* @param {string} required
|
|
*/
|
|
export function roleAllows(role, required) {
|
|
const have = ROLE_RANK[role] || 0
|
|
const need = ROLE_RANK[required] || ROLE_RANK[Roles.admin]
|
|
return have >= need
|
|
}
|
|
|
|
/**
|
|
* Minimum role required per method (default admin for unknown).
|
|
*/
|
|
export const MethodRoles = Object.freeze({
|
|
// session
|
|
handshake: Roles.viewer,
|
|
ping: Roles.viewer,
|
|
getServerInfo: Roles.viewer,
|
|
getAuthStatus: Roles.viewer,
|
|
setDisplayName: Roles.viewer,
|
|
|
|
// agent / node metadata
|
|
getNodeInfo: Roles.viewer,
|
|
getHealth: Roles.viewer,
|
|
|
|
// metrics discovery + query
|
|
listContexts: Roles.viewer,
|
|
getContext: Roles.viewer,
|
|
listCharts: Roles.viewer,
|
|
getChart: Roles.viewer,
|
|
queryData: Roles.viewer,
|
|
getAllMetrics: Roles.viewer,
|
|
getWeights: Roles.viewer,
|
|
|
|
// AI / QVAC tool-friendly composites (viewer read)
|
|
getHostSnapshot: Roles.viewer,
|
|
searchCharts: Roles.viewer,
|
|
summarizeChart: Roles.viewer,
|
|
investigateHost: Roles.viewer,
|
|
hotMetrics: Roles.viewer,
|
|
relatedCharts: Roles.viewer,
|
|
compareChartWindows: Roles.viewer,
|
|
summarizeCharts: Roles.viewer,
|
|
|
|
// live subscription control
|
|
subscribeMetrics: Roles.viewer,
|
|
unsubscribeMetrics: Roles.viewer,
|
|
subscribeAnomalies: Roles.viewer,
|
|
unsubscribeAnomalies: Roles.viewer,
|
|
|
|
// anomalies + alerts (read)
|
|
listAnomalies: Roles.viewer,
|
|
listAlerts: Roles.viewer,
|
|
getAlert: Roles.viewer,
|
|
/** Anomaly source: viewer; audit/journal enforced admin inside handler */
|
|
queryLogs: Roles.viewer,
|
|
|
|
/** Live process table (Linux /proc) */
|
|
listProcesses: Roles.viewer,
|
|
|
|
// alerts / thresholds (write)
|
|
setAlertConfig: Roles.operator,
|
|
ackAlert: Roles.operator,
|
|
silenceAlert: Roles.operator,
|
|
|
|
// jobs (on-demand collection / maintenance)
|
|
listJobs: Roles.viewer,
|
|
runJob: Roles.operator,
|
|
cancelJob: Roles.operator,
|
|
|
|
// HyperDB peer links / db info
|
|
getDbInfo: Roles.viewer,
|
|
listPeerLinks: Roles.viewer,
|
|
linkPeer: Roles.admin,
|
|
unlinkPeer: Roles.admin,
|
|
|
|
// Data Manager — retention + storage
|
|
getStorageInfo: Roles.viewer,
|
|
getRetentionConfig: Roles.viewer,
|
|
setRetentionConfig: Roles.admin,
|
|
pruneHistory: Roles.admin,
|
|
|
|
// parent / fleet aggregation
|
|
getFleetHealth: Roles.viewer,
|
|
listChildPeers: Roles.viewer,
|
|
|
|
// admin / fleet
|
|
mintInvite: Roles.admin,
|
|
listPeers: Roles.admin,
|
|
revokePeer: Roles.admin,
|
|
exportSnapshot: Roles.admin,
|
|
})
|
|
|
|
/**
|
|
* String method names for typed client calls.
|
|
*/
|
|
export const Methods = Object.freeze(
|
|
Object.fromEntries(Object.keys(MethodRoles).map((k) => [k, k]))
|
|
)
|
|
|
|
/**
|
|
* Server → client push event names (protomux-rpc events).
|
|
*/
|
|
export const Pushes = Object.freeze({
|
|
metrics: 'push:metrics',
|
|
anomaly: 'push:anomaly',
|
|
alert: 'push:alert',
|
|
health: 'push:health',
|
|
job: 'push:job',
|
|
system: 'push:system',
|
|
})
|
|
|
|
/**
|
|
* Map push channel → UI event type.
|
|
*/
|
|
export const PushToType = Object.freeze({
|
|
[Pushes.metrics]: 'metrics',
|
|
[Pushes.anomaly]: 'anomaly',
|
|
[Pushes.alert]: 'alert',
|
|
[Pushes.health]: 'health',
|
|
[Pushes.job]: 'job',
|
|
[Pushes.system]: 'system',
|
|
})
|
|
|
|
/** Methods treated as hot-path (skip heavy audit / schema). */
|
|
export const HotMethods = Object.freeze(
|
|
new Set([
|
|
Methods.ping,
|
|
Methods.queryData,
|
|
Methods.subscribeMetrics,
|
|
Methods.unsubscribeMetrics,
|
|
Methods.getAllMetrics,
|
|
Methods.listProcesses,
|
|
Methods.getHostSnapshot,
|
|
Methods.searchCharts,
|
|
Methods.summarizeChart,
|
|
Methods.investigateHost,
|
|
Methods.hotMetrics,
|
|
Methods.relatedCharts,
|
|
Methods.compareChartWindows,
|
|
Methods.summarizeCharts,
|
|
])
|
|
)
|