/** * Network RPC handlers. */ import { docker } from '../services/docker.js' import * as validation from '../utils/validation.js' export function registerNetworkHandlers(session) { session.respond('listNetworks', async () => { const networks = await docker.listNetworks() const containers = await docker.listContainers({ all: true }) const networkUsage = {} for (const container of containers) { const nets = container.NetworkSettings?.Networks if (!nets) continue for (const networkName of Object.keys(nets)) { if (!networkUsage[networkName]) networkUsage[networkName] = [] networkUsage[networkName].push({ id: container.Id, name: container.Names[0]?.replace(/^\//, '') || container.Id.substring(0, 12), state: container.State, }) } } return { type: 'networks', data: networks.map((network) => ({ ...network, usage: networkUsage[network.Name] || [], })), } }) session.respond('createNetwork', async (args) => { const name = validation.sanitizeString(args.name, 128) if (!name) throw new Error('Network name required') const networkConfig = { Name: name, Driver: args.driver || 'bridge', CheckDuplicate: true, Internal: Boolean(args.internal), Attachable: args.attachable !== false, EnableIPv6: Boolean(args.enableIPv6 || args.ipv6), Labels: args.labels && typeof args.labels === 'object' ? args.labels : undefined, } // Auto-fill IPAM when client asks (or subnet provided) let subnet = args.subnet let gateway = args.gateway if ((!subnet || args.autoIPAM) && networkConfig.Driver === 'bridge') { const { suggestNetworkIPAM } = await import('../utils/suggestions.js') const sug = await suggestNetworkIPAM() if (!subnet && sug.subnet) { subnet = sug.subnet gateway = gateway || sug.gateway } } if (subnet || gateway || args.ipRange) { networkConfig.IPAM = { Config: [ { ...(subnet ? { Subnet: subnet } : {}), ...(gateway ? { Gateway: gateway } : {}), ...(args.ipRange ? { IPRange: args.ipRange } : {}), }, ], } } if (args.options && typeof args.options === 'object') { networkConfig.Options = args.options } const network = await docker.createNetwork(networkConfig) return { success: true, message: `Network "${name}" created successfully`, data: network.id, applied: { name, driver: networkConfig.Driver, subnet, gateway }, } }) session.respond('removeNetwork', async (args) => { await docker.getNetwork(args.id).remove() return { success: true, message: `Network ${args.id} removed` } }) session.respond('inspectNetwork', async (args) => { const networkData = await docker.getNetwork(args.id).inspect() return { type: 'networkConfig', data: networkData } }) session.respond('connectNetwork', async (args) => { await docker.getNetwork(args.networkId).connect({ Container: args.containerId }) return { success: true, message: 'Container connected to network' } }) session.respond('disconnectNetwork', async (args) => { await docker .getNetwork(args.networkId) .disconnect({ Container: args.containerId, Force: args.force || false }) return { success: true, message: 'Container disconnected from network' } }) session.respond('pruneNetworks', async (args) => { const opts = {} if (args.filters) opts.filters = args.filters const result = await docker.pruneNetworks(opts) return { success: true, type: 'pruneNetworks', message: 'Unused networks pruned', data: result, } }) }