Class: Frpc::Admin

Inherits:
Object
  • Object
show all
Defined in:
lib/frpc/admin.rb

Overview

Thin wrapper over the frpc admin HTTP API (webServer.* in frpc.toml).

webServer.addr = "127.0.0.1"
webServer.port = 7400
webServer.user = "admin"
webServer.password = "hunter2"

Endpoints, as registered by client/admin_api.go:

GET  /healthz            (no auth)
GET  /api/status         per-proxy state
GET  /api/config         current config file contents
PUT  /api/config         overwrite the config file
GET  /api/reload         re-read the config file, diff, apply
POST /api/stop           graceful shutdown
GET/POST/PUT/DELETE /api/store/proxies*, /api/store/visitors*  (frp >= 0.68)

Defined Under Namespace

Classes: Error, ResponseError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host: "127.0.0.1", port: 7400, user: nil, password: nil, open_timeout: 2, read_timeout: 10) ⇒ Admin

Returns a new instance of Admin.



39
40
41
42
43
44
45
46
# File 'lib/frpc/admin.rb', line 39

def initialize(host: "127.0.0.1", port: 7400, user: nil, password: nil, open_timeout: 2, read_timeout: 10)
  @host = host
  @port = Integer(port)
  @user = user
  @password = password
  @open_timeout = open_timeout
  @read_timeout = read_timeout
end

Instance Attribute Details

#hostObject (readonly)

Returns the value of attribute host.



37
38
39
# File 'lib/frpc/admin.rb', line 37

def host
  @host
end

#portObject (readonly)

Returns the value of attribute port.



37
38
39
# File 'lib/frpc/admin.rb', line 37

def port
  @port
end

#userObject (readonly)

Returns the value of attribute user.



37
38
39
# File 'lib/frpc/admin.rb', line 37

def user
  @user
end

Instance Method Details

#configObject

The config file frpc was started with, as a string.



75
76
77
# File 'lib/frpc/admin.rb', line 75

def config
  get("/api/config")
end

#config=(toml) ⇒ Object

Overwrite the config file on the frpc host. Does NOT apply it — call reload afterwards, which is what frpc reload -c ... does internally.



81
82
83
# File 'lib/frpc/admin.rb', line 81

def config=(toml)
  put("/api/config", toml)
end

#delete(path) ⇒ Object



137
138
139
# File 'lib/frpc/admin.rb', line 137

def delete(path)
  request(Net::HTTP::Delete.new(path))
end

#delete_store_proxy(name) ⇒ Object



111
112
113
# File 'lib/frpc/admin.rb', line 111

def delete_store_proxy(name)
  delete("/api/store/proxies/#{escape(name)}")
end

#delete_store_visitor(name) ⇒ Object



119
120
121
# File 'lib/frpc/admin.rb', line 119

def delete_store_visitor(name)
  delete("/api/store/visitors/#{escape(name)}")
end

#get(path) ⇒ Object

--- verbs



125
126
127
# File 'lib/frpc/admin.rb', line 125

def get(path)
  request(Net::HTTP::Get.new(path))
end

#healthy?Boolean

true once the admin server is listening. Never raises — this is the readiness probe, so a connection refused is an expected answer.

Returns:

  • (Boolean)


50
51
52
53
54
55
# File 'lib/frpc/admin.rb', line 50

def healthy?
  request(Net::HTTP::Get.new("/healthz"), auth: false)
  true
rescue Error
  false
end

#post(path, body = nil, content_type: nil) ⇒ Object



129
130
131
# File 'lib/frpc/admin.rb', line 129

def post(path, body = nil, content_type: nil)
  request(build(Net::HTTP::Post, path, body, content_type))
end

#put(path, body = nil, content_type: nil) ⇒ Object



133
134
135
# File 'lib/frpc/admin.rb', line 133

def put(path, body = nil, content_type: nil)
  request(build(Net::HTTP::Put, path, body, content_type))
end

#put_store_proxy(name, config) ⇒ Object



107
108
109
# File 'lib/frpc/admin.rb', line 107

def put_store_proxy(name, config)
  put("/api/store/proxies/#{escape(name)}", JSON.generate(config), content_type: "application/json")
end

#put_store_visitor(name, config) ⇒ Object



115
116
117
# File 'lib/frpc/admin.rb', line 115

def put_store_visitor(name, config)
  put("/api/store/visitors/#{escape(name)}", JSON.generate(config), content_type: "application/json")
end

#reload(new_toml = nil) ⇒ Object

Re-read the config file and create/update/delete proxies to match. Optionally writes new_toml first.



87
88
89
90
# File 'lib/frpc/admin.rb', line 87

def reload(new_toml = nil)
  self.config = new_toml if new_toml
  get("/api/reload")
end

#statusObject

Per-proxy state: name, type, status ("running" / "start error" / ...), err, local_addr, plugin, remote_addr. Keyed by proxy type.



70
71
72
# File 'lib/frpc/admin.rb', line 70

def status
  get("/api/status")
end

#stopObject

Graceful shutdown. The HTTP response comes back before the process exits.



93
94
95
# File 'lib/frpc/admin.rb', line 93

def stop
  post("/api/stop")
end

#store_proxiesObject

--- store API (frp >= 0.68), only meaningful with a store source configured



99
100
101
# File 'lib/frpc/admin.rb', line 99

def store_proxies
  get("/api/store/proxies")
end

#store_visitorsObject



103
104
105
# File 'lib/frpc/admin.rb', line 103

def store_visitors
  get("/api/store/visitors")
end

#wait_until_healthy(timeout: 10, interval: 0.1) ⇒ Object

Blocks until healthy?, then returns self. Raises after the deadline.



58
59
60
61
62
63
64
65
66
# File 'lib/frpc/admin.rb', line 58

def wait_until_healthy(timeout: 10, interval: 0.1)
  deadline = monotonic_now + timeout
  loop do
    return self if healthy?
    raise Error, "frpc admin server never came up on #{host}:#{port}" if monotonic_now >= deadline

    sleep interval
  end
end