Sambex.Connection (sambex v0.2.0)

View Source

GenServer for maintaining persistent SMB connections.

This module provides a connection-based API that stores credentials securely in GenServer state and avoids passing them on every operation. Connections can be anonymous (referenced by PID) or named (referenced by atom) for easy access throughout your application.

Benefits of Connection API

  • Security: Credentials stored in process state, not passed around
  • Performance: Avoids reconnection overhead on each operation
  • Fault Tolerance: Full OTP supervision support with automatic restarts
  • Multiple Shares: Easy management of connections to different SMB shares
  • Elixir Idioms: Follows GenServer and OTP patterns

Connection Types

Anonymous Connections

Referenced by PID, suitable for short-lived operations:

{:ok, conn} = Sambex.Connection.connect("smb://server/share", "user", "pass")
Sambex.Connection.list_dir(conn, "/")
Sambex.Connection.disconnect(conn)

Named Connections

Referenced by atom, ideal for long-lived application connections:

{:ok, _} = Sambex.Connection.start_link([
  url: "smb://fileserver/documents",
  username: "user", 
  password: "pass",
  name: :documents
])

# Use throughout your application
Sambex.Connection.read_file(:documents, "/report.pdf")

Supervised Connections

Managed by the connection supervisor for production use:

{:ok, conn} = Sambex.ConnectionSupervisor.start_connection([
  url: "smb://server/share",
  username: "user",
  password: "pass", 
  name: :production_share
])

Complete Example

# Start named connections for different purposes
{:ok, _} = Sambex.Connection.start_link([
  url: "smb://fileserver/app-data",
  username: System.get_env("SMB_USER"),
  password: System.get_env("SMB_PASS"),
  name: :app_data
])

{:ok, _} = Sambex.Connection.start_link([
  url: "smb://backup-server/backups", 
  username: System.get_env("BACKUP_USER"),
  password: System.get_env("BACKUP_PASS"),
  name: :backups
])

# Perform operations using named connections
{:ok, files} = Sambex.Connection.list_dir(:app_data, "/uploads")

for {filename, :file} <- files do
  # Process each file
  {:ok, content} = Sambex.Connection.read_file(:app_data, "/uploads/#{filename}")

  # Backup processed files
  processed = process_file(content)
  Sambex.Connection.write_file(:backups, "/processed/#{filename}", processed)
end

Error Handling

All functions return standard {:ok, result} or {:error, reason} tuples:

case Sambex.Connection.read_file(:docs, "/important.pdf") do
  {:ok, content} -> 
    save_to_local(content)
  {:error, :enoent} -> 
    Logger.warn("File not found: /important.pdf")
  {:error, :eacces} ->
    Logger.error("Permission denied accessing /important.pdf") 
  {:error, reason} ->
    Logger.error("Unexpected error: #{inspect(reason)}")
end

Path Handling

All file paths are relative to the share root specified in the connection URL:

# Connection to smb://server/documents
{:ok, conn} = Sambex.Connection.connect("smb://server/documents", "user", "pass")

# These paths are relative to /documents on the server
Sambex.Connection.list_dir(conn, "/")          # Lists /documents/ 
Sambex.Connection.read_file(conn, "/file.txt") # Reads /documents/file.txt
Sambex.Connection.list_dir(conn, "/reports")   # Lists /documents/reports/

Production Integration

For production applications, integrate connections into your supervision tree:

# In your application.ex
children = [
  {Sambex.Connection, [
    url: "smb://production-server/app-files",
    username: Application.get_env(:my_app, :smb_username),
    password: Application.get_env(:my_app, :smb_password),
    name: :app_files
  ]}
]

Connection Lifecycle

Connections are GenServer processes that:

  1. Initialize with SMB credentials and URL
  2. Handle calls for SMB operations, forwarding to the underlying NIF
  3. Maintain state with connection details for the session
  4. Clean up automatically when the process terminates

The actual SMB connection is managed by the underlying libsmbclient library.

Summary

Functions

Returns a specification to start this module under a supervisor.

Convenience function to start a connection and return the PID.

Delete a file from the SMB share.

Stop a connection.

Download a file from the SMB share to local filesystem.

Get file statistics/metadata from the SMB share.

List files and directories in an SMB directory.

Move/rename a file on the SMB share.

Read a file from the SMB share.

Start a connection GenServer.

Upload a local file to the SMB share.

Write a file to the SMB share.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

connect(url, username, password)

Convenience function to start a connection and return the PID.

Examples

{:ok, conn} = Sambex.Connection.connect("smb://server/share", "user", "pass")
Sambex.Connection.list_dir(conn, "/")

delete_file(conn_or_name, path)

Delete a file from the SMB share.

Parameters

  • conn_or_name - Connection PID or registered name
  • path - Path to the file relative to share root

Examples

:ok = Sambex.Connection.delete_file(conn, "/temp.txt")

disconnect(conn_or_name)

Stop a connection.

Examples

:ok = Sambex.Connection.disconnect(conn)
:ok = Sambex.Connection.disconnect(:my_share)

download_file(conn_or_name, remote_path, local_path)

Download a file from the SMB share to local filesystem.

Parameters

  • conn_or_name - Connection PID or registered name
  • remote_path - Remote path relative to share root
  • local_path - Local file path

Examples

:ok = Sambex.Connection.download_file(conn, "/remote/file.txt", "/local/file.txt")

get_file_stats(conn_or_name, path)

Get file statistics/metadata from the SMB share.

Parameters

  • conn_or_name - Connection PID or registered name
  • path - Path to the file relative to share root

Examples

{:ok, stats} = Sambex.Connection.get_file_stats(conn, "/file.txt")

list_dir(conn_or_name, path)

List files and directories in an SMB directory.

Parameters

  • conn_or_name - Connection PID or registered name
  • path - Path relative to the share root

Examples

Sambex.Connection.list_dir(conn, "/")
Sambex.Connection.list_dir(:my_share, "/documents")

move_file(conn_or_name, source_path, dest_path)

Move/rename a file on the SMB share.

Parameters

  • conn_or_name - Connection PID or registered name
  • source_path - Source path relative to share root
  • dest_path - Destination path relative to share root

Examples

:ok = Sambex.Connection.move_file(conn, "/old.txt", "/new.txt")

read_file(conn_or_name, path)

Read a file from the SMB share.

Parameters

  • conn_or_name - Connection PID or registered name
  • path - Path to the file relative to share root

Examples

{:ok, content} = Sambex.Connection.read_file(conn, "/readme.txt")

start_link(opts)

Start a connection GenServer.

Options

  • :url - SMB URL (required)
  • :username - Username for authentication (required)
  • :password - Password for authentication (required)
  • :name - Optional name for the connection process

Examples

# Anonymous connection
{:ok, pid} = Sambex.Connection.start_link(
  url: "smb://server/share",
  username: "user",
  password: "pass"
)

# Named connection
{:ok, pid} = Sambex.Connection.start_link(
  url: "smb://server/share", 
  username: "user",
  password: "pass",
  name: :my_share
)

upload_file(conn_or_name, local_path, remote_path)

Upload a local file to the SMB share.

Parameters

  • conn_or_name - Connection PID or registered name
  • local_path - Local file path
  • remote_path - Remote path relative to share root

Examples

:ok = Sambex.Connection.upload_file(conn, "/local/file.txt", "/remote/file.txt")

write_file(conn_or_name, path, content)

Write a file to the SMB share.

Parameters

  • conn_or_name - Connection PID or registered name
  • path - Path to the file relative to share root
  • content - Binary content to write

Examples

:ok = Sambex.Connection.write_file(conn, "/output.txt", "Hello World")