tablestore-ruby-sdk 0.0.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/lib/consts.rb +44 -0
- data/lib/protobuf/ots.proto +374 -0
- data/lib/protobuf/ots_filiter.proto +48 -0
- data/lib/protobuf/ots_filiter_pb.rb +55 -0
- data/lib/protobuf/ots_pb.rb +307 -0
- data/lib/tablestore-ruby-sdk.rb +99 -0
- data/lib/tablestore/connection.rb +22 -0
- data/lib/tablestore/crc8_auto.rb +36 -0
- data/lib/tablestore/error.rb +57 -0
- data/lib/tablestore/main.rb +51 -0
- data/lib/tablestore/metadata.rb +413 -0
- data/lib/tablestore/ots.rb +481 -0
- data/lib/tablestore/plain_buffer_coded_input_stream.rb +217 -0
- data/lib/tablestore/plain_buffer_coded_output_stream.rb +252 -0
- data/lib/tablestore/plain_buffer_crc8.rb +21 -0
- data/lib/tablestore/plain_buffer_input_stream.rb +92 -0
- data/lib/tablestore/plain_buffer_output_stream.rb +59 -0
- data/lib/tablestore/protocol.rb +161 -0
- metadata +117 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'tablestore/crc8_auto'
|
2
|
+
|
3
|
+
class PlainBufferCrc8
|
4
|
+
class << self
|
5
|
+
def crc_string(crc, bytes)
|
6
|
+
Digest::CRC8Auto.new.crc8(crc, bytes.to_s).checksum
|
7
|
+
end
|
8
|
+
|
9
|
+
def crc_int8(crc, byte)
|
10
|
+
Digest::CRC8Auto.new.crc8(crc, [byte].pack('C*')).checksum
|
11
|
+
end
|
12
|
+
|
13
|
+
def crc_int32(crc, byte)
|
14
|
+
Digest::CRC8Auto.new.crc8(crc, [byte].pack('i')).checksum
|
15
|
+
end
|
16
|
+
|
17
|
+
def crc_int64(crc, byte)
|
18
|
+
Digest::CRC8Auto.new.crc8(crc, [byte].pack('q')).checksum
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'tablestore/error'
|
2
|
+
|
3
|
+
class PlainBufferInputStream
|
4
|
+
def initialize(data_buffer)
|
5
|
+
@buffer = data_buffer
|
6
|
+
@cur_pos = 0
|
7
|
+
@last_tag = 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def is_at_end?
|
11
|
+
@buffer.length == @cur_pos
|
12
|
+
end
|
13
|
+
|
14
|
+
def read_tag
|
15
|
+
if is_at_end?
|
16
|
+
@last_tag = 0
|
17
|
+
return 0
|
18
|
+
end
|
19
|
+
@last_tag = read_raw_byte
|
20
|
+
@last_tag.ord
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_last_tag_was(tag)
|
24
|
+
@last_tag.ord == tag
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_last_tag
|
28
|
+
@last_tag.ord
|
29
|
+
end
|
30
|
+
|
31
|
+
def read_raw_byte
|
32
|
+
raise TableStoreClientError.new("Read raw byte encountered EOF.") if is_at_end?
|
33
|
+
pos = @cur_pos
|
34
|
+
@cur_pos += 1
|
35
|
+
if @buffer[pos].is_a?(Fixnum)
|
36
|
+
[@buffer[pos]].chr
|
37
|
+
else
|
38
|
+
@buffer[pos]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def read_raw_little_endian64
|
43
|
+
read_bytes(8).unpack('q<')[0]
|
44
|
+
end
|
45
|
+
|
46
|
+
def read_raw_little_endian32
|
47
|
+
read_bytes(4).unpack('i<')[0]
|
48
|
+
end
|
49
|
+
|
50
|
+
def read_boolean
|
51
|
+
read_bytes(1).unpack('C')[0] == 1
|
52
|
+
end
|
53
|
+
|
54
|
+
def read_double
|
55
|
+
read_bytes(8).unpack('q<')[0]
|
56
|
+
end
|
57
|
+
|
58
|
+
def read_int32
|
59
|
+
read_bytes(4).unpack('i<')[0]
|
60
|
+
end
|
61
|
+
|
62
|
+
def read_int64
|
63
|
+
read_bytes(8).unpack('q<')[0]
|
64
|
+
end
|
65
|
+
|
66
|
+
def read_bytes(size)
|
67
|
+
raise TableStoreClientError.new("Read bytes encountered EOF.") if @buffer.length - @cur_pos < size
|
68
|
+
tmp_pos = @cur_pos
|
69
|
+
@cur_pos += size
|
70
|
+
@buffer[tmp_pos, size]
|
71
|
+
end
|
72
|
+
|
73
|
+
def read_utf_string(size)
|
74
|
+
raise TableStoreClientError.new("Read bytes encountered EOF.") if @buffer.length - @cur_pos < size
|
75
|
+
utf_str = @buffer[@cur_pos, size]
|
76
|
+
@cur_pos += size
|
77
|
+
utf_str.encode('utf-8') if utf_str.is_a?(String)
|
78
|
+
utf_str
|
79
|
+
end
|
80
|
+
|
81
|
+
def last_tag
|
82
|
+
@last_tag
|
83
|
+
end
|
84
|
+
|
85
|
+
def cur_pos
|
86
|
+
@cur_pos
|
87
|
+
end
|
88
|
+
|
89
|
+
def buffer
|
90
|
+
@buffer
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'tablestore/error'
|
2
|
+
|
3
|
+
class PlainBufferOutputStream
|
4
|
+
def initialize(capacity)
|
5
|
+
@buffer = []
|
6
|
+
@capacity = capacity
|
7
|
+
end
|
8
|
+
|
9
|
+
def is_full?
|
10
|
+
@capacity <= @buffer.length
|
11
|
+
end
|
12
|
+
|
13
|
+
def count
|
14
|
+
@buffer.length
|
15
|
+
end
|
16
|
+
|
17
|
+
def remain
|
18
|
+
@capacity - count
|
19
|
+
end
|
20
|
+
|
21
|
+
def clear
|
22
|
+
@buffer.clear
|
23
|
+
end
|
24
|
+
|
25
|
+
def write_raw_byte(value)
|
26
|
+
raise TableStoreClientError.new("The buffer is full") if is_full?
|
27
|
+
@buffer << [value].pack("C*")
|
28
|
+
end
|
29
|
+
|
30
|
+
def write_raw_little_endian32(value)
|
31
|
+
write_bytes([value].pack("i"))
|
32
|
+
end
|
33
|
+
|
34
|
+
def write_raw_little_endian64(value)
|
35
|
+
write_bytes([value].pack("q"))
|
36
|
+
end
|
37
|
+
|
38
|
+
def write_double(value)
|
39
|
+
write_bytes([value].pack("d"))
|
40
|
+
end
|
41
|
+
|
42
|
+
def write_boolean(value)
|
43
|
+
bool_value = value ? 1 : 0
|
44
|
+
write_bytes([bool_value].pack("C"))
|
45
|
+
end
|
46
|
+
|
47
|
+
def write_bytes(value)
|
48
|
+
raise TableStoreClientError.new("The buffer is full.") if @buffer.length + value.length > @capacity
|
49
|
+
bytes = ''
|
50
|
+
value.to_s.each_byte do |b|
|
51
|
+
bytes += [b].pack("C*")
|
52
|
+
end
|
53
|
+
@buffer << bytes
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_buffer
|
57
|
+
@buffer
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
class OTSProtocol
|
4
|
+
$api_version = '2015-12-31'
|
5
|
+
$user_agent = 'table-store-ruby'
|
6
|
+
|
7
|
+
encoder_class = OTSProtoBufferEncoder.new
|
8
|
+
decoder_class = OTSProtoBufferDecoder.new
|
9
|
+
|
10
|
+
$api_list = [
|
11
|
+
'CreateTable',
|
12
|
+
'ListTable',
|
13
|
+
'DeleteTable',
|
14
|
+
'DescribeTable',
|
15
|
+
'UpdateTable',
|
16
|
+
'GetRow',
|
17
|
+
'PutRow',
|
18
|
+
'UpdateRow',
|
19
|
+
'DeleteRow',
|
20
|
+
'BatchGetRow',
|
21
|
+
'BatchWriteRow',
|
22
|
+
'GetRange'
|
23
|
+
]
|
24
|
+
|
25
|
+
def initialize(user_id, user_key, sts_token, instance_name, encoding, logger)
|
26
|
+
@user_id = user_id
|
27
|
+
@user_key = user_key
|
28
|
+
@sts_token = sts_token
|
29
|
+
@instance_name = instance_name
|
30
|
+
@encoding = encoding
|
31
|
+
@encoder = encoder_class(encoding)
|
32
|
+
@decoder = decoder_class(encoding)
|
33
|
+
@logger = logger
|
34
|
+
end
|
35
|
+
|
36
|
+
def make_headers_string(headers)
|
37
|
+
headers.map{|k,v| "#{k.downcase}:#{v.strip}" if k.include?('x-ots-') and k != 'x-ots-signature'}.sort.join('\n')
|
38
|
+
end
|
39
|
+
|
40
|
+
def call_signature_method(signature_string)
|
41
|
+
salt = Digest::SHA1.digest(signature_string)
|
42
|
+
Base64.encode64(HMAC::SHA1.digest(UserSecret, salt)).strip
|
43
|
+
end
|
44
|
+
|
45
|
+
def make_request_signature(query, headers)
|
46
|
+
signature_string = query + '\n' + 'POST' + '\n\n'
|
47
|
+
|
48
|
+
headers_string = make_headers_string(headers)
|
49
|
+
signature_string += headers_string + '\n'
|
50
|
+
call_signature_method(signature_string)
|
51
|
+
end
|
52
|
+
|
53
|
+
def make_headers(body, query)
|
54
|
+
md5 = Base64.encode64(Digest::MD5.new.digest(body)).gsub(/\n/, '')
|
55
|
+
date = Time.now.strftime('%Y-%m-%dT%H:%M:%S.000Z')
|
56
|
+
|
57
|
+
headers = {
|
58
|
+
'x-ots-date': date,
|
59
|
+
'x-ots-apiversion': $api_version,
|
60
|
+
'x-ots-accesskeyid': @user_id,
|
61
|
+
'x-ots-instancename': @instance_name,
|
62
|
+
'x-ots-contentmd5': md5,
|
63
|
+
}
|
64
|
+
|
65
|
+
headers['x-ots-ststoken'] = @sts_token if @sts_token.present?
|
66
|
+
|
67
|
+
signature = make_request_signature(query, headers)
|
68
|
+
headers['x-ots-signature'] = signature
|
69
|
+
headers['User-Agent'] = $user_agent
|
70
|
+
headers
|
71
|
+
end
|
72
|
+
|
73
|
+
def make_response_signature(query, headers)
|
74
|
+
uri = query
|
75
|
+
headers_string = make_headers_string(headers)
|
76
|
+
|
77
|
+
signature_string = headers_string + '\n' + uri
|
78
|
+
signature = call_signature_method(signature_string)
|
79
|
+
signature
|
80
|
+
end
|
81
|
+
|
82
|
+
def check_headers(headers, body, status=nil)
|
83
|
+
# check the response headers and process response body if needed.
|
84
|
+
|
85
|
+
header_names = [
|
86
|
+
'x-ots-contentmd5',
|
87
|
+
'x-ots-requestid',
|
88
|
+
'x-ots-date',
|
89
|
+
'x-ots-contenttype',
|
90
|
+
]
|
91
|
+
|
92
|
+
if status >= 200 and status < 300
|
93
|
+
header_names.each do |name|
|
94
|
+
raise TableStoreClientError.new("#{name} is missing in response header.") unless headers.include?name
|
95
|
+
|
96
|
+
if headers.include?'x-ots-contentmd5'
|
97
|
+
md5 = Base64.encode64(Digest::MD5.new.digest(body)).gsub(/\n/, '')
|
98
|
+
end
|
99
|
+
raise TableStoreClientError.new('MD5 mismatch in response.') if md5 != headers['x-ots-contentmd5']
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def check_authorization(query, headers, status=nil)
|
105
|
+
auth = headers.get('authorization')
|
106
|
+
if auth.nil?
|
107
|
+
if status >= 200 and status < 300
|
108
|
+
raise TableStoreClientError.new('"Authorization" is missing in response header.')
|
109
|
+
else
|
110
|
+
return
|
111
|
+
end
|
112
|
+
end
|
113
|
+
# 1, check authorization
|
114
|
+
unless auth.include?('OTS ')
|
115
|
+
raise TableStoreClientError.new('Invalid Authorization in response.')
|
116
|
+
end
|
117
|
+
# 2, check accessid
|
118
|
+
access_id, signature = auth[4..-1].split(':')
|
119
|
+
if access_id != self.user_id
|
120
|
+
raise TableStoreClientError.new('Invalid accesskeyid in response.')
|
121
|
+
end
|
122
|
+
# 3, check signature
|
123
|
+
# decode the byte type
|
124
|
+
if signature != make_response_signature(query, headers)
|
125
|
+
raise TableStoreClientError.new('Invalid signature in response.')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def make_request(api_name)
|
130
|
+
raise TableStoreClientError("API #{api_name} is not supported.") if $api_list.exclude?api_name
|
131
|
+
body = encoder.encode_request(api_name, *args)
|
132
|
+
query = '/' + api_name
|
133
|
+
headers = make_headers(body, query)
|
134
|
+
return query, headers, body
|
135
|
+
end
|
136
|
+
|
137
|
+
def get_request_id_string(headers)
|
138
|
+
request_id = headers.get('x-ots-requestid')
|
139
|
+
request_id = "" if request_id.nil?
|
140
|
+
request_id
|
141
|
+
end
|
142
|
+
|
143
|
+
def parse_response(api_name, status, headers, body)
|
144
|
+
raise TableStoreClientError.new("API #{api_name} is not supported.") unless api_list.include?(api_name)
|
145
|
+
begin
|
146
|
+
hash, proto = decoder.decode_response(api_name, body)
|
147
|
+
rescue => e
|
148
|
+
request_id = get_request_id_string(headers)
|
149
|
+
error_message = "Response format is invalid, #{e}, RequestID: #{request_id}, " \
|
150
|
+
"HTTP status: #{status}, Body: #{body}."
|
151
|
+
self.logger.error(error_message)
|
152
|
+
raise TableStoreClientError.new(error_message, status)
|
153
|
+
end
|
154
|
+
hash
|
155
|
+
end
|
156
|
+
|
157
|
+
# def handle_error(api_name, query, status, reason, headers, body)
|
158
|
+
#
|
159
|
+
# end
|
160
|
+
|
161
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tablestore-ruby-sdk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- seveninches
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-01-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rest-client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: protobuf
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.8'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.8'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: digest-crc
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.4'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: os
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
description: A simple tablestore gem
|
70
|
+
email: lijinghao333@aliyun.com
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files: []
|
74
|
+
files:
|
75
|
+
- lib/consts.rb
|
76
|
+
- lib/protobuf/ots.proto
|
77
|
+
- lib/protobuf/ots_filiter.proto
|
78
|
+
- lib/protobuf/ots_filiter_pb.rb
|
79
|
+
- lib/protobuf/ots_pb.rb
|
80
|
+
- lib/tablestore-ruby-sdk.rb
|
81
|
+
- lib/tablestore/connection.rb
|
82
|
+
- lib/tablestore/crc8_auto.rb
|
83
|
+
- lib/tablestore/error.rb
|
84
|
+
- lib/tablestore/main.rb
|
85
|
+
- lib/tablestore/metadata.rb
|
86
|
+
- lib/tablestore/ots.rb
|
87
|
+
- lib/tablestore/plain_buffer_coded_input_stream.rb
|
88
|
+
- lib/tablestore/plain_buffer_coded_output_stream.rb
|
89
|
+
- lib/tablestore/plain_buffer_crc8.rb
|
90
|
+
- lib/tablestore/plain_buffer_input_stream.rb
|
91
|
+
- lib/tablestore/plain_buffer_output_stream.rb
|
92
|
+
- lib/tablestore/protocol.rb
|
93
|
+
homepage: http://rubygems.org/gems/tablestore-ruby-sdk
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
metadata: {}
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 2.6.10
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: tablestore
|
117
|
+
test_files: []
|