Connect, log in and keep the session

View as Markdown

Do this once at the start of every program: check that the server answers and what it supports, log in, and close the session when you are done. A long-running program also keeps its session alive.

Calls

Step Call Session
Server version QueryVersion not needed
Server features GetServerCapabilities not needed
Log in to a vault LogIn creates one
Session and vault GetVaultSessionInfo needed
Keep the session KeepAlive needed
End the session LogOut needed

Code

Python

# No session is needed for these calls.
with MFilesClient.from_env(CLIENT_NAME, log_in=False) as client:
    version_service = client.stub(IRPCQueryVersion_pb2_grpc.IRPCQueryVersionStub)
    version = version_service.QueryVersion(IRPCQueryVersion_pb2.QueryVersionRequest())
    print(f"Server version: {decode_version(version.server_version)}")

    login = client.stub(IRPCLogin_pb2_grpc.IRPCLoginStub)
    capabilities = login.GetServerCapabilities(
        IRPCLogin_pb2.GetServerCapabilitiesRequest()).server_capabilities
    print(f"Server capabilities: file_streaming={capabilities.file_streaming}, "
          f"facet_search={capabilities.facet_search}")

    session = client.log_in()
    print(f"Logged in as {session.account_name}; "
          f"keep-alive interval {session.keep_alive_interval_in_seconds} s")

    info = login.GetVaultSessionInfo(
        IRPCLogin_pb2.GetVaultSessionInfoRequest()).vault_session_info
    print(f"Vault: {info.vault_display_name} {info.vault_guid}")
    # From the trailers of the calls so far.
    structure_version = client.metadata_structure_version
    print(f"Metadata structure version: "
          f"{'not reported' if structure_version is None else structure_version}")

    # A long-running program calls KeepAlive within the keep-alive interval.
    login.KeepAlive(IRPCLogin_pb2.KeepAliveRequest())
    print("KeepAlive: ok")

    client.log_out()
    print("Logged out")

Source: python/recipes/connect.py

C#

// No session is needed for these calls.
await using var connection = MFilesConnection.Open(settings);

var versionService = new IRPCQueryVersion.IRPCQueryVersionClient(connection.CallInvoker);
var version = await versionService.QueryVersionAsync(new QueryVersionRequest());
Console.WriteLine($"Server version: {DecodeVersion(version.ServerVersion)}");

var login = new IRPCLogin.IRPCLoginClient(connection.CallInvoker);
var capabilities = (await login.GetServerCapabilitiesAsync(new GetServerCapabilitiesRequest()))
    .ServerCapabilities;
Console.WriteLine($"Server capabilities: file_streaming={capabilities.FileStreaming}, " +
    $"facet_search={capabilities.FacetSearch}");

var session = await connection.LogInAsync(settings, RecipeHelpers.ClientName);
Console.WriteLine($"Logged in as {session.AccountName}; " +
    $"keep-alive interval {session.KeepAliveIntervalInSeconds} s");

var info = (await login.GetVaultSessionInfoAsync(new GetVaultSessionInfoRequest())).VaultSessionInfo;
Console.WriteLine($"Vault: {info.VaultDisplayName} {info.VaultGuid}");
Console.WriteLine($"Metadata structure version: {connection.MetadataStructureVersion?.ToString() ?? "not reported"}");

// A long-running program calls KeepAlive within the keep-alive interval.
await login.KeepAliveAsync(new KeepAliveRequest());
Console.WriteLine("KeepAlive: ok");

await connection.LogOutAsync();
Console.WriteLine("Logged out");

Source: csharp/Recipes/Connect.cs

Go

// Dial only creates the channel. Calls without a session work right away.
client, err := mfilesclient.Dial(cfg)
if err != nil {
	return err
}
defer client.Close()

version, err := mfiles.NewIRPCQueryVersionClient(client.Conn).QueryVersion(ctx,
	&mfiles.QueryVersionRequest{})
if err != nil {
	return err
}
fmt.Println("Server version:", mfilesclient.VersionString(version.GetServerVersion()))

login := mfiles.NewIRPCLoginClient(client.Conn)
capabilities, err := login.GetServerCapabilities(ctx, &mfiles.GetServerCapabilitiesRequest{})
if err != nil {
	return err
}
fmt.Printf("Server capabilities: file_streaming=%v, facet_search=%v\n",
	capabilities.GetServerCapabilities().GetFileStreaming(),
	capabilities.GetServerCapabilities().GetFacetSearch())

// Log in. From now on every call carries the session ID.
session, err := client.LogIn(ctx, cfg)
if err != nil {
	return err
}
fmt.Printf("Logged in as %s; keep-alive interval %d s\n",
	session.GetAccountName(), session.GetKeepAliveIntervalInSeconds())

info, err := login.GetVaultSessionInfo(ctx, &mfiles.GetVaultSessionInfoRequest{})
if err != nil {
	return err
}
fmt.Printf("Vault: %s %s\n", info.GetVaultSessionInfo().GetVaultDisplayName(),
	info.GetVaultSessionInfo().GetVaultGuid())
// The latest value from the mfiles-metadata-version-bin trailer of the calls so far.
if metadataStructureVersion, ok := client.MetadataStructureVersion(); ok {
	fmt.Println("Metadata structure version:", metadataStructureVersion)
} else {
	fmt.Println("Metadata structure version: not reported")
}

// Call KeepAlive at least every keep-alive interval on long runs; other calls do not extend
// the session.
if _, err := login.KeepAlive(ctx, &mfiles.KeepAliveRequest{}); err != nil {
	return err
}
fmt.Println("KeepAlive: ok")

if err := client.LogOut(ctx); err != nil {
	return err
}
fmt.Println("Logged out")

Source: go/recipes/connect/main.go

Output against an on-premises server:

Server version: 26.11.16645.0
Server capabilities: file_streaming=True, facet_search=False
Logged in as grpcdocs.user; keep-alive interval 450 s
Vault: gRPC Docs Samples {7BBEA0BC-40D8-4BCB-A67D-8A3ACFBDB575}
Metadata structure version: 1024
KeepAlive: ok
Logged out

The two capability flags are examples. file_streaming does not mean that the streaming file transfer service can be used; see Files for the flags that matter for uploads.

Find the vault by its name

LogIn needs the vault's GUID. A program that knows only the vault's name, or wants to let the user pick a vault, finds the GUID first:

  1. LogIn with login_data.vault_guid set to {00000000-0000-0000-0000-000000000000}. This opens a server-level session.
  2. GetVaults with exclude_vaults_user_cannot_access true lists the vaults the user can log in to. Each has guid and display_name.
  3. LogInWithSession with the server-level session in mfiles-session-id-bin and the chosen vault's GUID in login_data.vault_guid returns a vault session, without authenticating again. Then log out the server-level session.

Python (the helper switch_to_vault does step 3):

client.config.vault = SERVER_LEVEL
client.log_in()
vaults = client.stub(IRPCVaults_pb2_grpc.IRPCVaultsStub).GetVaults(
    IRPCVaults_pb2.GetVaultsRequest(exclude_vaults_user_cannot_access=True)).vaults
for vault in vaults:
    print(f"{vault.display_name}: {vault.guid}")
matches = [v for v in vaults if not name or v.display_name.casefold() == name.casefold()]
if not matches:
    raise SystemExit(f"No vault named '{name}' that this user can access")
session = client.switch_to_vault(matches[0].guid)

Source: python/recipes/find_vault.py

response = self.login.LogInWithSession(IRPCLogin_pb2.LogInWithSessionRequest(
    client_data=self._client_data(),
    login_data=structs_pb2.LoginData(server_hostname=self.config.host,
                                     vault_guid=vault_guid)))
self.log_out()  # The server-level session; the new vault session stays valid.
self.config.vault = vault_guid
self.session_id = response.session_data.session_id
self.session = response.session_data

Source: python/mfiles_client.py

See Binding the session to a vault.

Pitfalls

See also