Module: Frpc::Ruby

Defined in:
lib/frpc/ruby.rb,
lib/frpc/ruby/version.rb

Overview

Locates the frpc executable this gem should run.

The gem ships as one platform gem per supported target, each carrying the matching CGO_ENABLED=0 binary from the upstream frp release under exe//. The plain "ruby" platform gem carries no binary at all; on an unsupported architecture the user installs frpc themselves and points FRPC_INSTALL_DIR at it.

Defined Under Namespace

Classes: ExecutableNotFoundError, UnsupportedPlatformError

Constant Summary collapse

PLATFORMS =

gem platform => upstream frp release target suffix

{
  "arm64-darwin"    => "darwin_arm64",
  "x86_64-darwin"   => "darwin_amd64",
  "aarch64-linux"   => "linux_arm64",
  "arm-linux"       => "linux_arm",
  "x86_64-linux"    => "linux_amd64",
  "x64-mingw-ucrt"  => "windows_amd64",
  "x64-mingw32"     => "windows_amd64",
  "aarch64-mingw-ucrt" => "windows_arm64",
}.freeze
PACKAGED_PLATFORMS =

Platforms we actually publish a gem for. x64-mingw32 resolves at runtime (old rubies report that platform string) but shares the ucrt gem's binary, so it is not built separately.

PLATFORMS.keys - ["x64-mingw32"]
VERSION =

Mirrors the upstream frp release we vendor. If the wrapper itself needs a release without an upstream bump, append a fourth segment ("0.70.1.1") — UPSTREAM_VERSION drops it again when building download URLs.

"0.70.1"
UPSTREAM_VERSION =
VERSION.split(".").first(3).join(".")

Class Method Summary collapse

Class Method Details

.exe_nameObject



74
75
76
# File 'lib/frpc/ruby.rb', line 74

def exe_name
  Gem.win_platform? ? "frpc.exe" : "frpc"
end

.executable(exe_path: nil) ⇒ Object

Resolution order, first hit wins:

1. an explicit exe_path: argument
2. FRPC_INSTALL_DIR / FRPC_PATH (a directory or a full path)
3. the binary vendored into this gem for the current platform
4. frpc on PATH


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/frpc/ruby.rb', line 40

def executable(exe_path: nil)
  override = exe_path || ENV["FRPC_INSTALL_DIR"] || ENV["FRPC_PATH"]
  return resolve_override(override) unless override.nil? || override.empty?

  return vendored_executable if vendored_executable
  return path_executable if path_executable

  raise ExecutableNotFoundError, <<~MSG
    Cannot find the frpc executable for platform #{platform}.

    This usually means the platform gem for #{platform} was not installed.
    Bundler only locks the platforms it has seen, so try:

        bundle lock --add-platform #{platform}

    If #{platform} is not a platform frpc-ruby ships a binary for, install
    frpc yourself from https://github.com/fatedier/frp/releases and set
    FRPC_INSTALL_DIR to the directory containing it (or FRPC_PATH to the
    executable itself).
  MSG
end

.path_executableObject



88
89
90
91
92
93
94
# File 'lib/frpc/ruby.rb', line 88

def path_executable
  ENV.fetch("PATH", "")
     .split(File::PATH_SEPARATOR)
     .reject(&:empty?)
     .map { |dir| File.join(dir, exe_name) }
     .find { |file| File.executable?(file) && !File.directory?(file) }
end

.platformObject

e.g. "x86_64-linux", "arm64-darwin"



63
64
65
# File 'lib/frpc/ruby.rb', line 63

def platform
  @platform ||= [:cpu, :os].map { |part| Gem::Platform.local.public_send(part) }.join("-")
end

.upstream_target(gem_platform = platform) ⇒ Object

The upstream release target for the running platform, e.g. "linux_amd64".



68
69
70
71
72
# File 'lib/frpc/ruby.rb', line 68

def upstream_target(gem_platform = platform)
  PLATFORMS.fetch(gem_platform) do
    raise UnsupportedPlatformError, "frpc-ruby has no upstream frp build for #{gem_platform}"
  end
end

.vendored_executableObject



83
84
85
86
# File 'lib/frpc/ruby.rb', line 83

def vendored_executable
  candidate = vendored_path
  candidate if File.exist?(candidate)
end

.vendored_path(gem_platform = platform, name = exe_name) ⇒ Object

Path the packaging task writes to, and the path executable/2 reads back.



79
80
81
# File 'lib/frpc/ruby.rb', line 79

def vendored_path(gem_platform = platform, name = exe_name)
  File.expand_path(File.join(__dir__, "..", "..", "exe", gem_platform, name))
end