Remote Services

The client-side surface for consuming a Viper Service over the network. Every class here is a ServiceRemote* type: the dynamic, metadata-driven handle returned by ServiceRemote.connect() and the introspected pool / function objects hanging off it.

The single entry point is ServiceRemote.connect() — everything else is discovered at runtime from the service’s embedded DSM. The same handle connects to any Viper service with no per-service codegen; the Kibo-generated typed proxies (function_pool_remotes, attachment_function_pool_remotes) are a comfort layer that wraps this same surface. For what a service is, the two pool kinds, and the server side, see Service.

Note

The server side (Viper::Service, Viper::ServiceServer) is C++ only — it is not part of the dsviper Python module. Python is a client of Viper services.

Quick Start

The universal dynamic client — connect, then dispatch by pool and function name through a runtime dictionary. No service-specific import:

from dsviper import Definitions, ServiceRemote

defs = Definitions()
s = ServiceRemote.connect("localhost", "54328", defs)

# Dispatch by pool name → function name → call.
result = s.function_pool_funcs("Tools")["add"](32, 10)   # 42

s.close()

The five-line connection scaffold ships with dsviper-tools as service_client.py; any REPL session or schema-agnostic adapter extends from there.

See also

For the typed-proxy path (Kibo-generated, per-pool, IDE-friendly) and the Remote-Local protocol behind stateful calls, see Anatomy of a Service and Remote-Local Protocol.

Introspecting a live service

Because the service ships its DSM inside the binary, a connected client can enumerate the whole typed surface — pools, functions, prototypes, and the documentation authored in the DSM — without any prior knowledge of the schema.

List the pools. Stateless and stateful pools are reported separately, each carrying its name and embedded documentation:

for pool in s.function_pools():              # ServiceRemoteFunctionPool
    print("function_pool", pool.name(), "—", pool.documentation())

for pool in s.attachment_function_pools():   # ServiceRemoteAttachmentFunctionPool
    print("attachment_function_pool", pool.name(), "—", pool.documentation())

Walk the functions, with prototypes and docs. Each function exposes its FunctionPrototype (return type and named parameters) and its embedded documentation; stateful functions additionally report whether they mutate:

pool = s.function_pools()[0]
funcs = s.function_pool_funcs(pool.name())   # names via dir()

for name in dir(funcs):
    fn = pool.check(name)                     # ServiceRemoteFunctionPoolFunction
    proto = fn.prototype()                    # FunctionPrototype
    args = ", ".join(f"{ty} {nm}" for nm, ty in proto.parameters())
    print(f"  {proto.return_type()} {name}({args})  # {fn.documentation()}")

# For attachment pools, the per-function `.is_mutable()` reflects the
# DSM `mutable` marker.

Re-emit the service as DSM. The most direct view is to reconstruct the DSM source of the live service — pools, function signatures, and the embedded documentation, exactly as written in the .dsm — from the connection alone:

dsm = s.to_dsm_definitions()                  # DSMDefinitions
print(dsm.to_dsm())                           # DSM language text (docs included)

to_dsm() includes documentation by default; pass html=True for a marked-up rendering, or use Html.dsm_definitions() to render the same model as a styled HTML fragment.

Choosing the Right Entry Point

Need

Class / Method

Example

Connect to a service

ServiceRemote.connect()

s = ServiceRemote.connect(host, port, defs)

Call a stateless function

ServiceRemoteFunctionPoolFunctions

s.function_pool_funcs("Tools")["add"](1, 2)

Call a stateful function

ServiceRemoteAttachmentFunctionPoolFunctions

s.attachment_function_pool_funcs("PlayerModel")["create"](m, ...)

List exposed pools

ServiceRemote.function_pools()

[p.name() for p in s.function_pools()]

Inspect a function signature

ServiceRemoteFunctionPoolFunction

pool.check("add").prototype().parameters()

Re-emit the service schema

ServiceRemote.to_dsm_definitions()

s.to_dsm_definitions().to_dsm()

Connection

dsviper.ServiceRemote

A class used to connect to a remote service.

Stateless Pools

The function_pool surface — pure functions, executed on the server, returned immediately.

dsviper.ServiceRemoteFunctionPools

A class used to represent the remote function pools.

dsviper.ServiceRemoteFunctionPool

A class used to represent a remote function pool.

dsviper.ServiceRemoteFunctionPoolFunctions

A class used to represent the functions of a pool.

dsviper.ServiceRemoteFunctionPoolFunction

A class used to represent a remote function.

dsviper.ServiceRemoteFunction

A class used to call a remote function.

Stateful Pools

The attachment_function_pool surface — functions that execute on the server but read and mutate the client’s AttachmentMutating through the Remote-Local protocol (see Remote-Local Protocol).

dsviper.ServiceRemoteAttachmentFunctionPools

A class used to represent the remote attachment pools.

dsviper.ServiceRemoteAttachmentFunctionPool

A class used to represent a remote attachment function pool.

dsviper.ServiceRemoteAttachmentFunctionPoolFunctions

A class used to represent the remote attachment functions.

dsviper.ServiceRemoteAttachmentFunctionPoolFunction

A class used to represent a remote attachment function.

dsviper.ServiceRemoteAttachmentFunction

A class used to call a remote attachment function.

See also

FunctionPrototype and the in-process pool classes (FunctionPool, Function) live in Core Utilities. The DSM model types returned by to_dsm_definitions (DSMDefinitions, DSMFunctionPool) are in DSM Introspection.