deskconn

package module
v0.1.0-alpha.6d98c25 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 25, 2026 License: MIT Imports: 50 Imported by: 0

README

Deskconn

Deskconn is a desktop management suite. It consists of two main tools: a desktop daemon and a command-line client.

Installation

curl -fsSL https://get.deskconn.com | sh

deskconnd

The desktop daemon responsible for registering and exposing desktop APIs to the Deskconn ecosystem. It runs in the background and enables remote management and control of the desktop.

Run
make run-deskconnd

deskconn

A command-line tool used to manage desktops. It can attach a desktop to the cloud, execute commands, transfer files, manage printers, and perform other administrative tasks.

Build
make build-deskconn
Run

Run the resulting binary to see available commands and help:

./deskconn
Supported commands

Command line interface looks like this:

usage: deskconn <command> [<args> ...]

Deskconn control CLI

Flags:
  --[no-]help  Show context-sensitive help (also try --help-long and --help-man).

Commands:
help [<command>...]
    Show help.


attach [<flags>]
    Attach a device

    -n, --name=NAME            Device name
    -u, --username=USERNAME    Username
    -p, --password=PASSWORD    Password
        --[no-]password-stdin  Read password from stdin

detach [<flags>]
    Detach device

    -u, --username=USERNAME    Username
    -p, --password=PASSWORD    Password
        --[no-]password-stdin  Read password from stdin

login [<flags>]
    Login and store credentials

    -u, --username=USERNAME    Username
    -p, --password=PASSWORD    Password
        --[no-]password-stdin  Read password from stdin

file ls [<flags>] <target>
    List files on a device

    --mode=MODE  Connection mode: 'p2p' uses direct WebRTC, 'routed' uses router, default auto-migrates from routed to p2p

file mv [<flags>] <src> <dst>
    Move or rename a file or directory on a device

    --mode=MODE  Connection mode: 'p2p' uses direct WebRTC, 'routed' uses router, default auto-migrates from routed to p2p

file cp [<flags>] <src> <dst>
    Copy files to/from/between devices

    -r, --[no-]recursive  Copy directories recursively
        --mode=MODE       Connection mode: 'p2p' uses direct WebRTC, 'routed' uses router, default auto-migrates from routed to p2p

file rm [<flags>] <target>
    Remove a file or directory on a device

    --mode=MODE  Connection mode: 'p2p' uses direct WebRTC, 'routed' uses router, default auto-migrates from routed to p2p

shell [<flags>] <device>
    Start interactive shell

    --mode=MODE  Connection mode: 'p2p' uses direct WebRTC, 'routed' uses router, default auto-migrates from routed to p2p

exec [<flags>] <device> <command>...
    Run a command

    --[no-]p2p  Connect using WebRTC

print [<flags>] [<target>] [<file_path>]
    Print operations

    --[no-]enable         Enable receiving print jobs on this desktop
    --[no-]host-printers  Also allow remote clients to list this desktop's printers (use with --enable)
    --[no-]disable        Disable receiving print jobs on this desktop
    --[no-]status         Show whether this desktop accepts print jobs
    --ls=LS               List printers on a device (device name or alias)
    --[no-]p2p            Connect using WebRTC

port forward [<flags>] <device> [<ports>]
    Forward a local port to a port on the remote device

    -l, --local=LOCAL    Local port to listen on
    -r, --remote=REMOTE  Port on the remote device to connect to
        --[no-]p2p       Connect using WebRTC

ls [<flags>]
    List devices

    --[no-]refresh   Refresh device list from cloud
    --[no-]detailed  Show detailed output

whoami
    Show current user


logout
    Logout


config show
    Show config


config set <device> <key> <value>
    Set device alias


config unset <device> <key>
    Unset device alias


config edit
    Edit full config


self version
    Show the installed deskconn version


self update
    Check for updates and install the latest release

Documentation

Index

Constants

View Source
const (
	Realm                            = "io.xconn.deskconn"
	ProcedureDeskconnAttachDesktop   = "io.xconn.deskconn.desktop.attach"
	ProcedureDeskconnDetachDesktop   = "io.xconn.deskconn.desktop.detach"
	TopicDeskconnDesktopDetachFormat = "io.xconn.deskconn.desktop.%s.detach"
	MachineIDPath                    = "/etc/machine-id"
)
View Source
const (
	ProcedureListKeys     = "io.xconn.deskconn.desktop.access.key.list"
	TopicKeyAddedFormat   = "io.xconn.deskconn.desktop.%s.key.add"
	TopicKeyRemovedFormat = "io.xconn.deskconn.desktop.%s.key.remove"
)
View Source
const (
	ProcedureKeyExchange         = "io.xconn.deskconn.deskconnd.key.exchange"
	ProcedureScreenBrightnessGet = "io.xconn.deskconn.deskconnd.screen.brightness.get"
	ProcedureScreenBrightnessSet = "io.xconn.deskconn.deskconnd.screen.brightness.set"
	ProcedureScreenLock          = "io.xconn.deskconn.deskconnd.screen.lock"
	ProcedureScreenIsLocked      = "io.xconn.deskconn.deskconnd.screen.islocked"
	ProcedureShell               = "io.xconn.deskconn.deskconnd.shell"
	ProcedureExec                = "io.xconn.deskconn.deskconnd.exec"
	ProcedureFileBrowse          = "io.xconn.deskconn.deskconnd.file.browse"
	ProcedurePrinterList         = "io.xconn.deskconn.deskconnd.printer.list"
	ProcedurePrinterPrint        = "io.xconn.deskconn.deskconnd.printer.print"
	ProcedureFileRename          = "io.xconn.deskconn.deskconnd.file.rename"
	ProcedureFileDelete          = "io.xconn.deskconn.deskconnd.file.delete"
	ProcedureFileCopy            = "io.xconn.deskconn.deskconnd.file.copy"
	ProcedureFileSearch          = "io.xconn.deskconn.deskconnd.file.search"
	ProcedureDeviceInfo          = "io.xconn.deskconn.deskconnd.device.info"
	ProcedureLogs                = "io.xconn.deskconn.deskconnd.logs"

	ProcedureMPRISPlayers   = "io.xconn.deskconn.deskconnd.mpris.players"
	ProcedureMPRISPlayPause = "io.xconn.deskconn.deskconnd.mpris.playpause"
	ProcedureMPRISPlay      = "io.xconn.deskconn.deskconnd.mpris.play"
	ProcedureMPRISPause     = "io.xconn.deskconn.deskconnd.mpris.pause"
	ProcedureMPRISNext      = "io.xconn.deskconn.deskconnd.mpris.next"
	ProcedureMPRISPrevious  = "io.xconn.deskconn.deskconnd.mpris.previous"

	ErrInvalidArgument = "wamp.error.invalid_argument"
	ErrOperationFailed = "wamp.error.operation_failed"
	ErrNotAuthorized   = "wamp.error.not_authorized"

	MetaTopicSessionLeave = "wamp.session.on_leave"
)
View Source
const (
	ProcedureWebRTCOffer     = "io.xconn.webrtc.offer"
	TopicAnswererOnCandidate = "io.xconn.webrtc.answerer.on_candidate"
	TopicOffererOnCandidate  = "io.xconn.webrtc.offerer.on_candidate"

	ProcedurePrincipalCreate = "io.xconn.deskconn.account.principal.create"
	ProcedurePrincipalDelete = "io.xconn.deskconn.account.principal.delete"
	ProcedureAccountGet      = "io.xconn.deskconn.account.get"

	ProcedureProxyShell       = "io.xconn.deskconn.deskconnd.proxy.shell"
	ProcedureProxyExec        = "io.xconn.deskconn.deskconnd.proxy.exec"
	ProcedureProxyFileOp      = "io.xconn.deskconn.deskconnd.proxy.file.op"
	ProcedureProxyDeviceInfo  = "io.xconn.deskconn.deskconnd.proxy.device.info"
	ProcedureProxyLogs        = "io.xconn.deskconn.deskconnd.proxy.logs"
	ProcedureLogin            = "io.xconn.deskconn.login"
	ProcedureLogout           = "io.xconn.deskconn.logout"
	ProcedureConnectedDevices = "io.xconn.deskconn.connected_devices"

	ProcedureListDesktop = "io.xconn.deskconn.desktop.list"

	ProcedureAppUpdateCheck = "io.xconn.deskconn.app.update.check"

	ProcedureCoturnCreate = "io.xconn.deskconn.coturn.credentials.create"

	LocalRealm = "io.xconn.deskconn.local"
	CloudRealm = "io.xconn.deskconn"

	ErrAuthenticationFailed = "wamp.error.authentication_failed"

	StunServerURL = "stun:stun.l.google.com:19302"
)
View Source
const (
	ProcedureFileDownload = "io.xconn.deskconn.deskconnd.file.download"
)
View Source
const (
	ProcedureFileUpload = "io.xconn.deskconn.deskconnd.file.upload"
)
View Source
const (
	ProcedurePortForward = "io.xconn.deskconn.deskconnd.port.forward"
)
View Source
const ProcedurePortReverse = "io.xconn.deskconn.deskconnd.port.reverse"

Variables

View Source
var BacklightBasePath = "/sys/class/backlight" //nolint: gochecknoglobals

Functions

func AdvertiseService

func AdvertiseService(hostname string, port int, realm string) (*zeroconf.Server, error)

func AllZeros

func AllZeros(b []byte) bool

func Attach

func Attach(username, password, desktopName string) error

func CallFileOp

func CallFileOp(deviceSession *xconn.Session, procedure string, payload []byte) ([]byte, error)

func CfgDirectory

func CfgDirectory() (string, error)

func CloudURI

func CloudURI() string

func ConnectCloudRealm

func ConnectCloudRealm(cfgDirectory string) (*xconn.Session, error)

func ConnectDeviceRealm

func ConnectDeviceRealm(ctx context.Context, realm, cfgDirectory string, useP2P bool) (*xconn.Session, error)

func ConnectWebrtc

func ConnectWebrtc(ctx context.Context, session *xconn.Session, realm, authid, privateKey,
	cfgDirectory string) (*xconn.Session, error)

func CreateX25519KeyPair

func CreateX25519KeyPair() (publicKey []byte, privateKey []byte, err error)

func CredentialsFilePath

func CredentialsFilePath() (string, error)

func DecryptChaCha20Poly1305

func DecryptChaCha20Poly1305(ciphertext, nonce, key []byte) ([]byte, error)

func DecryptPayload

func DecryptPayload(data, key []byte) ([]byte, error)

DecryptPayload decrypts a payload produced by EncryptPayload (nonce+ciphertext).

func DeriveKeyHKDF

func DeriveKeyHKDF(sharedSecret, info []byte) ([]byte, error)

func Detach

func Detach(session *xconn.Session, authID string) error

func DisablePrinting

func DisablePrinting() error

func EnablePrinterHosting

func EnablePrinterHosting() error

func EnablePrinting

func EnablePrinting() error

func EncryptChaCha20Poly1305

func EncryptChaCha20Poly1305(plaintext, key []byte) ([]byte, []byte, error)

func EncryptPayload

func EncryptPayload(plaintext, key []byte) ([]byte, error)

EncryptPayload encrypts plaintext and returns nonce+ciphertext concatenated.

func FetchTURNServers

func FetchTURNServers(session *xconn.Session) ([]xconnwebrtc.ICEServer, int64, error)

func ForwardLocalPort

func ForwardLocalPort(ctx context.Context, session *xconn.Session, remotePort, localPort string) error

func GetOrRefreshTURNServers

func GetOrRefreshTURNServers(ctx context.Context, authid, privKey, cfgDirectory string) ([]xconnwebrtc.ICEServer,
	error)

func Login

func Login(session *xconn.Session, username string) error

func PerformKeyExchange

func PerformKeyExchange(privateKey, peerPublicKey []byte) ([]byte, error)

func ProxyDeviceInfoHandler

func ProxyDeviceInfoHandler(clientSessions *ClientSessions, cfgDirectory string) xconn.InvocationHandler

func ProxyFileOpHandler

func ProxyFileOpHandler(clientSessions *ClientSessions, cfgDirectory string) xconn.InvocationHandler

func ProxyLogsHandler

func ProxyLogsHandler(proxyCalls *ProxyCalls, clientSessions *ClientSessions,
	cfgDirectory string) xconn.InvocationHandler

ProxyLogsHandler proxies ProcedureLogs using a cloud-first session with async WebRTC upgrade.

func ProxyProgressiveInvocationHandler

func ProxyProgressiveInvocationHandler(proxyCalls *ProxyCalls, clientSessions *ClientSessions,
	cfgDirectory, procedure string) xconn.InvocationHandler

func ProxyShellHandler

func ProxyShellHandler(proxyCalls *ProxyCalls, clientSessions *ClientSessions,
	cfgDirectory string) xconn.InvocationHandler

ProxyShellHandler proxies ProcedureShell with transparent PTY migration. On first connection it uses a cloud session for fast start, then upgrades to WebRTC in the background. When WebRTC is ready the daemon migrates the live PTY and stores the WebRTC session for future reuse. If a P2P session is already cached it is used directly with no migration needed.

func PullFiles

func PullFiles(session *xconn.Session, remotePath, localPath string, recursive bool) error

func PushFiles

func PushFiles(session *xconn.Session, localPath, remotePath string, recursive bool) error

func ReadCredentials

func ReadCredentials(cfgDirectory string) (string, string, error)

func RemoveCredentialsFiles

func RemoveCredentialsFiles(cfgDirectory string) error

func ReverseLocalPort

func ReverseLocalPort(ctx context.Context, session *xconn.Session, remotePort, localPort string) error

ReverseLocalPort calls ProcedurePortReverse on the remote device, which listens on remotePort. Incoming connections on the remote are forwarded to localhost:localPort.

func SetPrintMode

func SetPrintMode(mode PrintMode) error

func StartInteractiveCommand

func StartInteractiveCommand(session *xconn.Session, realm, procedureName string, args ...string) error

func StreamLogs

func StreamLogs(session *xconn.Session, realm, source string, follow bool, tailN int64, since string) error

func WritePrincipalsToFile

func WritePrincipalsToFile(principals []*CryptosignPrincipal) error

Types

type Authenticator

type Authenticator struct {
	sync.Mutex
	// contains filtered or unexported fields
}

func NewAuthenticator

func NewAuthenticator(principals []*CryptosignPrincipal) *Authenticator

func (*Authenticator) Authenticate

func (a *Authenticator) Authenticate(request auth.Request) (auth.Response, error)

func (*Authenticator) Methods

func (a *Authenticator) Methods() []auth.Method

func (*Authenticator) RetrievePrincipal

func (a *Authenticator) RetrievePrincipal(authid string) (*CryptosignPrincipal, bool)

func (*Authenticator) SetPrincipal

func (a *Authenticator) SetPrincipal(authid string, principal *CryptosignPrincipal)

func (*Authenticator) SetPrincipals

func (a *Authenticator) SetPrincipals(principals []*CryptosignPrincipal)

func (*Authenticator) SubscribeEvents

func (a *Authenticator) SubscribeEvents(session *xconn.Session, machineID string) error

type CPUTimes

type CPUTimes struct {
	User    float64 `json:"user"`
	System  float64 `json:"system"`
	Nice    float64 `json:"nice"`
	Idle    float64 `json:"idle"`
	IOWait  float64 `json:"iowait"`
	IRQ     float64 `json:"irq"`
	SoftIRQ float64 `json:"softirq"`
	Steal   float64 `json:"steal"`
}

type ClientSessions

type ClientSessions struct {
	sync.Mutex
	// contains filtered or unexported fields
}

func NewClientSessions

func NewClientSessions() *ClientSessions

func (*ClientSessions) DeleteDeviceSession

func (c *ClientSessions) DeleteDeviceSession(realm string)

func (*ClientSessions) DeviceSessions

func (c *ClientSessions) DeviceSessions() map[string]int64

func (*ClientSessions) EnsureDeviceSessionWithUpgrade

func (c *ClientSessions) EnsureDeviceSessionWithUpgrade(ctx context.Context, realm,
	cfgDirectory string) (*xconn.Session, <-chan *xconn.Session, error)

EnsureDeviceSessionWithUpgrade is like EnsureDeviceSession but also returns a channel that receives the WebRTC session when the background upgrade completes. If a connected session is already cached the channel is closed immediately.

func (*ClientSessions) EnsureP2PDeviceSession

func (c *ClientSessions) EnsureP2PDeviceSession(ctx context.Context, realm,
	cfgDirectory string) (*xconn.Session, error)

EnsureP2PDeviceSession returns the cached session if one exists. Otherwise it establishes a WebRTC connection synchronously — never falling back to cloud.

func (*ClientSessions) LoggedIn

func (c *ClientSessions) LoggedIn() bool

func (*ClientSessions) Login

func (c *ClientSessions) Login()

func (*ClientSessions) Logout

func (c *ClientSessions) Logout()

func (*ClientSessions) SessionByRealm

func (c *ClientSessions) SessionByRealm(authid string) (*xconn.Session, bool)

func (*ClientSessions) StoreDeviceSession

func (c *ClientSessions) StoreDeviceSession(realm string, session *xconn.Session)

type Config

type Config struct {
	Devices  []Device       `yaml:"devices"`
	Printing PrintingConfig `yaml:"printing,omitempty"`
}

type Credentials

type Credentials struct {
	Realm      string `json:"realm"`
	AuthID     string `json:"authid"`
	PublicKey  string `json:"public_key"`
	PrivateKey string `json:"private_key"` // #nosec
}

func EnsureCredentials

func EnsureCredentials() (*Credentials, error)

type CryptosignPrincipal

type CryptosignPrincipal struct {
	AuthID         string   `json:"authid"`
	AuthorizedKeys []string `json:"authorized_keys"`
	AuthRole       string   `json:"authrole"`
}

func ReadPrincipalsFromFile

func ReadPrincipalsFromFile() ([]*CryptosignPrincipal, error)

type Deskconn

type Deskconn struct {
	// contains filtered or unexported fields
}

func NewDeskconn

func NewDeskconn(screen *Screen, mpris *MPRIS) *Deskconn

func (*Deskconn) Register

func (d *Deskconn) Register(session *xconn.Session) error

type Device

type Device struct {
	Authid       string       `json:"authid" yaml:"authid"`
	ID           string       `json:"id" yaml:"id"`
	Name         string       `json:"name" yaml:"name"`
	Organization Organization `json:"organization" yaml:"organization"`
	Realm        string       `json:"realm" yaml:"realm"`
	Alias        string       `yaml:"alias"`
	Connected    bool         `yaml:"-" json:"-"`
}

func DevicesFromCfg

func DevicesFromCfg(cfgDirectory string) ([]Device, error)

func FetchDevicesFromCloud

func FetchDevicesFromCloud(cfgDirectory string) ([]Device, error)

type DeviceInfo

type DeviceInfo struct {
	CPUModel    string    `json:"cpu_model"`
	CPUPhysical int       `json:"cpu_physical"`
	CPULogical  int       `json:"cpu_logical"`
	CPUUsages   []float64 `json:"cpu_usages"`
	CPUTimes    CPUTimes  `json:"cpu_times"`

	RAMTotal     uint64 `json:"ram_total"`
	RAMFree      uint64 `json:"ram_free"`
	RAMUsed      uint64 `json:"ram_used"`
	RAMBuffCache uint64 `json:"ram_buff_cache"`
	RAMAvailable uint64 `json:"ram_available"`

	SwapTotal uint64 `json:"swap_total"`
	SwapFree  uint64 `json:"swap_free"`
	SwapUsed  uint64 `json:"swap_used"`

	DiskUsed  uint64 `json:"disk_used"`
	DiskFree  uint64 `json:"disk_free"`
	DiskTotal uint64 `json:"disk_total"`
}

type FileBrowseResult

type FileBrowseResult struct {
	Path       string      `json:"path"`
	HomePath   string      `json:"home_path"`
	ParentPath string      `json:"parent_path,omitempty"`
	Type       string      `json:"type"`
	Mode       string      `json:"mode"`
	Size       int64       `json:"size"`
	ModTime    time.Time   `json:"mod_time"`
	IsDir      bool        `json:"is_dir"`
	IsSymlink  bool        `json:"is_symlink"`
	LinkTarget string      `json:"link_target,omitempty"`
	Entries    []FileEntry `json:"entries,omitempty"`
}

type FileBrowser

type FileBrowser struct{}

func NewFileBrowser

func NewFileBrowser() *FileBrowser

func (*FileBrowser) Browse

func (f *FileBrowser) Browse(pathArg string) (*FileBrowseResult, error)

func (*FileBrowser) Copy

func (f *FileBrowser) Copy(srcPath, dstPath string) error

func (*FileBrowser) Delete

func (f *FileBrowser) Delete(path string) error

func (*FileBrowser) Rename

func (f *FileBrowser) Rename(oldPath, newPath string) error

func (*FileBrowser) Search

func (f *FileBrowser) Search(pathArg, query string, showHidden bool, sendKey []byte, inv *xconn.Invocation) error

type FileEntry

type FileEntry struct {
	Name       string    `json:"name"`
	Path       string    `json:"path"`
	Type       string    `json:"type"`
	Mode       string    `json:"mode"`
	Size       int64     `json:"size"`
	Hidden     bool      `json:"hidden"`
	ModTime    time.Time `json:"mod_time"`
	IsDir      bool      `json:"is_dir"`
	IsSymlink  bool      `json:"is_symlink"`
	LinkTarget string    `json:"link_target,omitempty"`
	ItemCount  *int      `json:"item_count,omitempty"`
	Thumbnail  string    `json:"thumbnail,omitempty"`
}

type MPRIS

type MPRIS struct {
	// contains filtered or unexported fields
}

func NewMPRIS

func NewMPRIS(conn *dbus.Conn) *MPRIS

func (*MPRIS) ListPlayers

func (m *MPRIS) ListPlayers() (map[string]string, error)

func (*MPRIS) Next

func (m *MPRIS) Next() error

func (*MPRIS) NextPlayer

func (m *MPRIS) NextPlayer(name string) error

func (*MPRIS) Pause

func (m *MPRIS) Pause() error

func (*MPRIS) PausePlayer

func (m *MPRIS) PausePlayer(name string) error

func (*MPRIS) Play

func (m *MPRIS) Play() error

func (*MPRIS) PlayPause

func (m *MPRIS) PlayPause() error

func (*MPRIS) PlayPausePlayer

func (m *MPRIS) PlayPausePlayer(name string) error

func (*MPRIS) PlayPlayer

func (m *MPRIS) PlayPlayer(name string) error

func (*MPRIS) Previous

func (m *MPRIS) Previous() error

func (*MPRIS) PreviousPlayer

func (m *MPRIS) PreviousPlayer(name string) error

type Organization

type Organization struct {
	ID   string `json:"id" yaml:"id"`
	Name string `json:"name" yaml:"name"`
}

type PrintJobStatus

type PrintJobStatus struct {
	JobID     string `json:"job_id"`
	Printer   string `json:"printer"`
	State     string `json:"state"`
	Message   string `json:"message,omitempty"`
	CreatedAt int64  `json:"created_at"`
}

type PrintMode

type PrintMode string
const (
	PrintModeDisabled PrintMode = "disabled"
	PrintModeAccept   PrintMode = "accept"
	PrintModeHost     PrintMode = "host"
)

func CurrentPrintMode

func CurrentPrintMode() (PrintMode, error)

type Printer

type Printer struct {
	// contains filtered or unexported fields
}

func NewPrinter

func NewPrinter() *Printer

func (*Printer) ExecutePrint

func (p *Printer) ExecutePrint(ctx context.Context, printer string, filename string, data []byte) error

type PrinterInfo

type PrinterInfo struct {
	Name     string `json:"name"`
	PPDModel string `json:"ppd"`
}

type PrintingConfig

type PrintingConfig struct {
	Mode PrintMode `yaml:"mode,omitempty"`
}

type ProxyCall

type ProxyCall struct {
	sync.Mutex
	// contains filtered or unexported fields
}

type ProxyCalls

type ProxyCalls struct {
	sync.Mutex
	// contains filtered or unexported fields
}

func NewProxyCalls

func NewProxyCalls() *ProxyCalls

func (*ProxyCalls) Delete

func (p *ProxyCalls) Delete(id uint64)

func (*ProxyCalls) Fetch

func (p *ProxyCalls) Fetch(id uint64) (*ProxyCall, bool)

func (*ProxyCalls) Store

func (p *ProxyCalls) Store(id uint64, c *ProxyCall)

type Screen

type Screen struct {
	// contains filtered or unexported fields
}

func NewScreen

func NewScreen(sessionBus, systemBus *dbus.Conn) *Screen

func (*Screen) GetBrightness

func (s *Screen) GetBrightness() (int, error)

func (*Screen) IsLocked

func (s *Screen) IsLocked() (bool, error)

func (*Screen) Lock

func (s *Screen) Lock() error

func (*Screen) SetBrightness

func (s *Screen) SetBrightness(percent int) error

type TURNCredentials

type TURNCredentials struct {
	ExpiresAt  int64    `json:"expires_at"`
	Username   string   `json:"username"`
	Credential string   `json:"credential"`
	URLs       []string `json:"urls"`
}

Directories

Path Synopsis
cmd
deskconn command
deskconnd command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL