herowebv/src/clients/zinit
2025-05-31 11:15:44 +03:00
..
client.v ... 2025-05-31 11:15:44 +03:00
openrpc.json ... 2025-05-31 11:15:44 +03:00
openrpc.v ... 2025-05-31 11:15:44 +03:00
README.md ... 2025-05-31 11:15:44 +03:00
test.v ... 2025-05-31 11:15:44 +03:00
types.v ... 2025-05-31 11:15:44 +03:00
zinit.v ... 2025-05-31 11:15:44 +03:00

Zinit Client Module

A well-documented V (Vlang) client library for interacting with the Zinit service manager via JSON-RPC over Unix socket.

Overview

This module provides a complete client implementation for the Zinit JSON-RPC API, allowing you to manage services, monitor system resources, and control the Zinit service manager programmatically.

Features

  • Service Management: Start, stop, monitor, and forget services
  • Service Configuration: Create, delete, and retrieve service configurations
  • System Control: Shutdown, reboot, and HTTP server management
  • Monitoring: Get service status, statistics, and resource usage
  • Logging: Stream current logs and subscribe to log updates
  • Error Handling: Comprehensive error handling with detailed error messages
  • Type Safety: Strongly typed structs for all API responses
  • Connection Management: Automatic connection handling with proper cleanup

Installation

Simply import the module in your V project:

import zinit

Quick Start

import zinit

fn main() {
    // Create a client with default socket path (/tmp/zinit.sock)
    mut client := zinit.new_default_client()
    
    // Or specify a custom socket path
    // mut client := zinit.new_client('/custom/path/to/zinit.sock')
    
    defer {
        client.disconnect()
    }
    
    // List all services
    services := client.service_list() or {
        eprintln('Error: ${err}')
        return
    }
    
    for name, state in services {
        println('${name}: ${state}')
    }
}

API Reference

Client Creation

new_client(socket_path string) &Client

Creates a new zinit client with a custom socket path.

new_default_client() &Client

Creates a new zinit client with the default socket path (/tmp/zinit.sock).

Connection Management

connect() !

Establishes a connection to the zinit Unix socket. Called automatically by API methods.

disconnect()

Closes the connection to the zinit Unix socket. Should be called when done with the client.

Service Management

service_list() !map[string]string

Lists all services managed by Zinit.

Returns: A map of service names to their current states.

services := client.service_list()!
for name, state in services {
    println('${name}: ${state}')
}

service_status(name string) !ServiceStatus

Shows detailed status information for a specific service.

Parameters:

  • name: The name of the service

Returns: ServiceStatus struct with detailed information.

status := client.service_status('redis')!
println('Service: ${status.name}')
println('State: ${status.state}')
println('PID: ${status.pid}')

service_start(name string) !

Starts a service.

Parameters:

  • name: The name of the service to start

service_stop(name string) !

Stops a service.

Parameters:

  • name: The name of the service to stop

service_monitor(name string) !

Starts monitoring a service. The service configuration is loaded from the config directory.

Parameters:

  • name: The name of the service to monitor

service_forget(name string) !

Stops monitoring a service. You can only forget a stopped service.

Parameters:

  • name: The name of the service to forget

service_kill(name string, signal string) !

Sends a signal to a running service.

Parameters:

  • name: The name of the service to send the signal to
  • signal: The signal to send (e.g., "SIGTERM", "SIGKILL")

Service Configuration

service_create(name string, config ServiceConfig) !string

Creates a new service configuration file.

Parameters:

  • name: The name of the service to create
  • config: The service configuration

Returns: Result message.

config := zinit.ServiceConfig{
    exec: '/usr/bin/redis-server'
    oneshot: false
    log: 'stdout'
    env: {
        'REDIS_PORT': '6379'
    }
    shutdown_timeout: 30
}

result := client.service_create('redis', config)!
println('Service created: ${result}')

service_delete(name string) !string

Deletes a service configuration file.

Parameters:

  • name: The name of the service to delete

Returns: Result message.

service_get(name string) !ServiceConfig

Gets a service configuration file.

Parameters:

  • name: The name of the service to get

Returns: ServiceConfig struct with the service configuration.

Service Statistics

service_stats(name string) !ServiceStats

Gets memory and CPU usage statistics for a service.

Parameters:

  • name: The name of the service to get stats for

Returns: ServiceStats struct with usage information.

stats := client.service_stats('redis')!
println('Memory Usage: ${stats.memory_usage / 1024 / 1024} MB')
println('CPU Usage: ${stats.cpu_usage}%')

System Operations

system_shutdown() !

Stops all services and powers off the system.

⚠️ Warning: This will actually shut down the system!

system_reboot() !

Stops all services and reboots the system.

⚠️ Warning: This will actually reboot the system!

system_start_http_server(address string) !string

Starts an HTTP/RPC server at the specified address.

Parameters:

  • address: The network address to bind the server to (e.g., "127.0.0.1:8080")

Returns: Result message.

system_stop_http_server() !

Stops the HTTP/RPC server if running.

Logging

stream_current_logs(name ?string) ![]string

Gets current logs from zinit and monitored services.

Parameters:

  • name: Optional service name filter. If provided, only logs from this service will be returned.

Returns: Array of log strings.

// Get all logs
all_logs := client.stream_current_logs(none)!

// Get logs for a specific service
redis_logs := client.stream_current_logs('redis')!

stream_subscribe_logs(name ?string) !string

Subscribes to log messages generated by zinit and monitored services.

Parameters:

  • name: Optional service name filter.

Returns: A single log message.

Note: For continuous streaming, call this method repeatedly.

API Discovery

rpc_discover() !map[string]interface{}

Returns the OpenRPC specification for the API.

Returns: The complete OpenRPC specification as a map.

Data Types

ServiceConfig

Represents the configuration for a zinit service.

struct ServiceConfig {
pub mut:
    exec             string            // Command to run
    oneshot          bool              // Whether the service should be restarted
    after            []string          // Services that must be running before this one starts
    log              string            // How to handle service output (null, ring, stdout)
    env              map[string]string // Environment variables for the service
    shutdown_timeout int               // Maximum time to wait for service to stop during shutdown
}

ServiceStatus

Represents the detailed status information for a service.

struct ServiceStatus {
pub mut:
    name   string            // Service name
    pid    int               // Process ID of the running service (if running)
    state  string            // Current state of the service (Running, Success, Error, etc.)
    target string            // Target state of the service (Up, Down)
    after  map[string]string // Dependencies of the service and their states
}

ServiceStats

Represents memory and CPU usage statistics for a service.

struct ServiceStats {
pub mut:
    name         string        // Service name
    pid          int           // Process ID of the service
    memory_usage i64           // Memory usage in bytes
    cpu_usage    f64           // CPU usage as a percentage (0-100)
    children     []ChildStats  // Stats for child processes
}

ChildStats

Represents statistics for a child process.

struct ChildStats {
pub mut:
    pid          int  // Process ID of the child process
    memory_usage i64  // Memory usage in bytes
    cpu_usage    f64  // CPU usage as a percentage (0-100)
}

Error Handling

The client provides comprehensive error handling through V's error system. All API methods that can fail return a result type (!).

ZinitError

Custom error type for zinit-specific errors.

struct ZinitError {
pub mut:
    code    int    // Error code
    message string // Error message
    data    string // Additional error data
}

Common error codes:

  • -32000: Service not found
  • -32001: Service already monitored
  • -32002: Service is up
  • -32003: Service is down
  • -32004: Invalid signal
  • -32005: Config error
  • -32006: Shutting down
  • -32007: Service already exists
  • -32008: Service file error

Examples

See example.v for comprehensive usage examples covering all API methods.

Basic Service Management

import zinit

fn manage_service() ! {
    mut client := zinit.new_default_client()
    defer { client.disconnect() }
    
    // Create a service
    config := zinit.ServiceConfig{
        exec: '/usr/bin/nginx'
        oneshot: false
        log: 'stdout'
        after: ['network']
    }
    
    client.service_create('nginx', config)!
    client.service_monitor('nginx')!
    client.service_start('nginx')!
    
    // Check status
    status := client.service_status('nginx')!
    println('Nginx is ${status.state}')
    
    // Get statistics
    stats := client.service_stats('nginx')!
    println('Memory: ${stats.memory_usage / 1024 / 1024} MB')
}

Log Monitoring

import zinit
import time

fn monitor_logs() ! {
    mut client := zinit.new_default_client()
    defer { client.disconnect() }
    
    // Get current logs
    logs := client.stream_current_logs(none)!
    for log in logs {
        println(log)
    }
    
    // Subscribe to new logs (simplified example)
    for i in 0..10 {
        log_entry := client.stream_subscribe_logs(none) or { continue }
        println('New log: ${log_entry}')
        time.sleep(1 * time.second)
    }
}

Thread Safety

The client is not thread-safe. If you need to use it from multiple threads, you should create separate client instances or implement your own synchronization.

Requirements

  • V compiler
  • Unix-like operating system (for Unix socket support)
  • Running Zinit service manager

License

This module follows the same license as the parent project.