antd 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE-APACHE +201 -0
- data/LICENSE-MIT +21 -0
- data/README.md +184 -0
- data/lib/antd/client.rb +675 -0
- data/lib/antd/discover.rb +132 -0
- data/lib/antd/errors.rb +73 -0
- data/lib/antd/grpc_client.rb +549 -0
- data/lib/antd/models.rb +198 -0
- data/lib/antd/v1/chunks_pb.rb +26 -0
- data/lib/antd/v1/chunks_services_pb.rb +32 -0
- data/lib/antd/v1/common_pb.rb +21 -0
- data/lib/antd/v1/data_pb.rb +31 -0
- data/lib/antd/v1/data_services_pb.rb +36 -0
- data/lib/antd/v1/files_pb.rb +25 -0
- data/lib/antd/v1/files_services_pb.rb +31 -0
- data/lib/antd/v1/health_pb.rb +18 -0
- data/lib/antd/v1/health_services_pb.rb +24 -0
- data/lib/antd/v1/upload_pb.rb +25 -0
- data/lib/antd/v1/upload_services_pb.rb +51 -0
- data/lib/antd/v1/wallet_pb.rb +22 -0
- data/lib/antd/v1/wallet_services_pb.rb +42 -0
- data/lib/antd/version.rb +5 -0
- data/lib/antd.rb +14 -0
- metadata +145 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbconfig"
|
|
4
|
+
|
|
5
|
+
module Antd
|
|
6
|
+
# Auto-discovers the antd daemon by reading the +daemon.port+ file that antd
|
|
7
|
+
# writes on startup.
|
|
8
|
+
#
|
|
9
|
+
# The file contains up to three lines: REST port (line 1), gRPC port (line 2),
|
|
10
|
+
# and optionally the daemon PID (line 3).
|
|
11
|
+
#
|
|
12
|
+
# If a PID is present and the process is no longer alive, the port file is
|
|
13
|
+
# considered stale and discovery returns empty.
|
|
14
|
+
#
|
|
15
|
+
# Port file location is platform-specific:
|
|
16
|
+
# - Windows: %APPDATA%\ant\sdk\daemon.port
|
|
17
|
+
# - macOS: ~/Library/Application Support/ant/sdk/daemon.port
|
|
18
|
+
# - Linux: $XDG_DATA_HOME/ant/sdk/daemon.port or ~/.local/share/ant/sdk/daemon.port
|
|
19
|
+
#
|
|
20
|
+
# The +sdk+ subdirectory keeps antd's port file separate from the ant-node
|
|
21
|
+
# daemon, which writes to the same +ant+ umbrella dir.
|
|
22
|
+
module Discover
|
|
23
|
+
PORT_FILE_NAME = "daemon.port"
|
|
24
|
+
DATA_DIR_NAME = "ant"
|
|
25
|
+
SDK_SUBDIR_NAME = "sdk"
|
|
26
|
+
|
|
27
|
+
# Reads the daemon.port file and returns the REST base URL
|
|
28
|
+
# (e.g. "http://127.0.0.1:8082").
|
|
29
|
+
#
|
|
30
|
+
# @return [String] the URL, or "" if the port file is not found
|
|
31
|
+
def self.daemon_url
|
|
32
|
+
rest, _ = read_port_file
|
|
33
|
+
return "" if rest == 0
|
|
34
|
+
|
|
35
|
+
"http://127.0.0.1:#{rest}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Reads the daemon.port file and returns the gRPC target
|
|
39
|
+
# (e.g. "127.0.0.1:50051").
|
|
40
|
+
#
|
|
41
|
+
# @return [String] the target, or "" if the port file is not found
|
|
42
|
+
def self.grpc_target
|
|
43
|
+
_, grpc = read_port_file
|
|
44
|
+
return "" if grpc == 0
|
|
45
|
+
|
|
46
|
+
"127.0.0.1:#{grpc}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @api private
|
|
50
|
+
def self.read_port_file
|
|
51
|
+
dir = data_dir
|
|
52
|
+
return [0, 0] if dir.empty?
|
|
53
|
+
|
|
54
|
+
path = File.join(dir, PORT_FILE_NAME)
|
|
55
|
+
return [0, 0] unless File.exist?(path)
|
|
56
|
+
|
|
57
|
+
lines = File.read(path).strip.split("\n")
|
|
58
|
+
rest_port = parse_port(lines[0])
|
|
59
|
+
grpc_port = parse_port(lines[1])
|
|
60
|
+
pid = parse_pid(lines[2])
|
|
61
|
+
|
|
62
|
+
return [0, 0] if pid > 0 && !process_alive?(pid)
|
|
63
|
+
|
|
64
|
+
[rest_port, grpc_port]
|
|
65
|
+
rescue StandardError
|
|
66
|
+
[0, 0]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @api private
|
|
70
|
+
def self.parse_port(str)
|
|
71
|
+
return 0 if str.nil?
|
|
72
|
+
|
|
73
|
+
s = str.strip
|
|
74
|
+
return 0 unless s.match?(/\A\d+\z/)
|
|
75
|
+
|
|
76
|
+
n = s.to_i
|
|
77
|
+
(n > 0 && n <= 65535) ? n : 0
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @api private
|
|
81
|
+
def self.data_dir
|
|
82
|
+
host_os = RbConfig::CONFIG["host_os"]
|
|
83
|
+
|
|
84
|
+
case host_os
|
|
85
|
+
when /mswin|mingw|cygwin/
|
|
86
|
+
appdata = ENV["APPDATA"]
|
|
87
|
+
return "" if appdata.nil? || appdata.empty?
|
|
88
|
+
|
|
89
|
+
File.join(appdata, DATA_DIR_NAME, SDK_SUBDIR_NAME)
|
|
90
|
+
when /darwin/
|
|
91
|
+
home = ENV["HOME"]
|
|
92
|
+
return "" if home.nil? || home.empty?
|
|
93
|
+
|
|
94
|
+
File.join(home, "Library", "Application Support", DATA_DIR_NAME, SDK_SUBDIR_NAME)
|
|
95
|
+
else
|
|
96
|
+
xdg = ENV["XDG_DATA_HOME"]
|
|
97
|
+
if xdg && !xdg.empty?
|
|
98
|
+
File.join(xdg, DATA_DIR_NAME, SDK_SUBDIR_NAME)
|
|
99
|
+
else
|
|
100
|
+
home = ENV["HOME"]
|
|
101
|
+
return "" if home.nil? || home.empty?
|
|
102
|
+
|
|
103
|
+
File.join(home, ".local", "share", DATA_DIR_NAME, SDK_SUBDIR_NAME)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# @api private
|
|
109
|
+
def self.parse_pid(str)
|
|
110
|
+
return 0 if str.nil?
|
|
111
|
+
|
|
112
|
+
s = str.strip
|
|
113
|
+
return 0 unless s.match?(/\A\d+\z/)
|
|
114
|
+
|
|
115
|
+
n = s.to_i
|
|
116
|
+
n > 0 ? n : 0
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# @api private
|
|
120
|
+
def self.process_alive?(pid)
|
|
121
|
+
Process.kill(0, pid)
|
|
122
|
+
true
|
|
123
|
+
rescue Errno::ESRCH
|
|
124
|
+
false
|
|
125
|
+
rescue Errno::EPERM
|
|
126
|
+
# Process exists but we lack permission to signal it — still alive.
|
|
127
|
+
true
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
private_class_method :read_port_file, :parse_port, :parse_pid, :process_alive?, :data_dir
|
|
131
|
+
end
|
|
132
|
+
end
|
data/lib/antd/errors.rb
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Antd
|
|
4
|
+
# Base error type for all antd errors.
|
|
5
|
+
class AntdError < StandardError
|
|
6
|
+
attr_reader :status_code
|
|
7
|
+
|
|
8
|
+
def initialize(message, status_code:)
|
|
9
|
+
@status_code = status_code
|
|
10
|
+
super("antd error #{status_code}: #{message}")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Invalid request parameters (HTTP 400).
|
|
15
|
+
class BadRequestError < AntdError
|
|
16
|
+
def initialize(message) = super(message, status_code: 400)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Insufficient funds or payment failure (HTTP 402).
|
|
20
|
+
class PaymentError < AntdError
|
|
21
|
+
def initialize(message) = super(message, status_code: 402)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Resource not found on the network (HTTP 404).
|
|
25
|
+
class NotFoundError < AntdError
|
|
26
|
+
def initialize(message) = super(message, status_code: 404)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Resource already exists (HTTP 409).
|
|
30
|
+
class AlreadyExistsError < AntdError
|
|
31
|
+
def initialize(message) = super(message, status_code: 409)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Version conflict or fork detected (HTTP 409).
|
|
35
|
+
class ForkError < AntdError
|
|
36
|
+
def initialize(message) = super(message, status_code: 409)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Payload too large (HTTP 413).
|
|
40
|
+
class TooLargeError < AntdError
|
|
41
|
+
def initialize(message) = super(message, status_code: 413)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Internal server error (HTTP 500).
|
|
45
|
+
class InternalError < AntdError
|
|
46
|
+
def initialize(message) = super(message, status_code: 500)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Daemon cannot reach the network (HTTP 502).
|
|
50
|
+
class NetworkError < AntdError
|
|
51
|
+
def initialize(message) = super(message, status_code: 502)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Service unavailable, e.g. wallet not configured (HTTP 503).
|
|
55
|
+
class ServiceUnavailableError < AntdError
|
|
56
|
+
def initialize(message) = super(message, status_code: 503)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Returns the appropriate error type for an HTTP status code.
|
|
60
|
+
def self.error_for_status(code, message)
|
|
61
|
+
case code
|
|
62
|
+
when 400 then BadRequestError.new(message)
|
|
63
|
+
when 402 then PaymentError.new(message)
|
|
64
|
+
when 404 then NotFoundError.new(message)
|
|
65
|
+
when 409 then AlreadyExistsError.new(message)
|
|
66
|
+
when 413 then TooLargeError.new(message)
|
|
67
|
+
when 500 then InternalError.new(message)
|
|
68
|
+
when 502 then NetworkError.new(message)
|
|
69
|
+
when 503 then ServiceUnavailableError.new(message)
|
|
70
|
+
else AntdError.new(message, status_code: code)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|