lolitado 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/.gitignore +1 -0
- data/README.md +69 -0
- data/lib/.DS_Store +0 -0
- data/lib/lolitado/api.rb +117 -0
- data/lib/lolitado/box.rb +44 -0
- data/lib/lolitado/db.rb +140 -0
- data/lib/lolitado/pool.rb +139 -0
- data/lib/{version.rb → lolitado/version.rb} +1 -1
- data/lib/lolitado.rb +78 -6
- data/lolitado.gemspec +22 -0
- metadata +12 -8
- data/lib/accessors.rb +0 -22
- data/lib/box.rb +0 -29
- data/lib/db.rb +0 -27
- data/lib/pool.rb +0 -109
- data/lib/request.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7215273662a496c04cf7766edd94711a0b7597b9b9aecd4e5986551617a65fc2
|
4
|
+
data.tar.gz: e41b90e0441c6ef8433b4d08608c18fb5782d51d411087cad69c7e536fb4c1b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 742ac304a6247c677d2cc71b443a86cef94a0cd16ee8880f5cb1634a44f66f9cd99bf092dbf6b69ccd4de57114b6990e5887ca14e05c29820e486676471911d9
|
7
|
+
data.tar.gz: 64581f1c3e9871efdfa1eeaf2109766a4acc77f4e34fefe130fc275589ee43d5603fa91a403173664965f451fd57d64cd8bd613fea2a6782938578f2596f9382
|
data/.DS_Store
ADDED
Binary file
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
lolitado*.gem
|
data/README.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# lolitado
|
2
|
+
Library for using database and API
|
3
|
+
|
4
|
+
----
|
5
|
+
## How to call database?
|
6
|
+
|
7
|
+
|
8
|
+
You need to do these things:
|
9
|
+
|
10
|
+
* put all sql in sql.yml or in code
|
11
|
+
* put database connect info in xx_db.yml
|
12
|
+
----
|
13
|
+
run case like
|
14
|
+
|
15
|
+
````ruby
|
16
|
+
pool = Lolitado:Pool.new('xx_db.yml')
|
17
|
+
db = pool.use(:db =>'db_name')
|
18
|
+
sql = "select * from identity.user where phone = '+86 139 0000 0000"
|
19
|
+
result = db.query(sql)
|
20
|
+
````
|
21
|
+
----
|
22
|
+
## How to call API?
|
23
|
+
|
24
|
+
----
|
25
|
+
run case like
|
26
|
+
|
27
|
+
````ruby
|
28
|
+
* Rest API
|
29
|
+
class TestRest
|
30
|
+
include Lolitado
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
base_uri 'https://xxx.com'
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_details_of_a_city city_slug, locale
|
37
|
+
add_headers({'Accept-Language' => locale})
|
38
|
+
request('get', "/cities/#{city_slug}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
* Graph API
|
43
|
+
class TestGraph
|
44
|
+
include Lolitado
|
45
|
+
|
46
|
+
def initialize
|
47
|
+
base_uri 'https://xxx.com'
|
48
|
+
end
|
49
|
+
|
50
|
+
def user_login payload
|
51
|
+
add_headers({'Content-Type' => "application/json"})
|
52
|
+
query = "mutation login($input: UserLoginInput!) {userLogin(input:$input) {authToken}}"
|
53
|
+
graph_request(query, payload)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
````
|
57
|
+
----
|
58
|
+
## How to encrypt/decrypt credential file?
|
59
|
+
|
60
|
+
* Initialize Box with secret key of environment variable
|
61
|
+
* file_encrypt to encrypt the file
|
62
|
+
* file_decrypt to decrypt the file
|
63
|
+
|
64
|
+
----
|
65
|
+
````ruby
|
66
|
+
box = Lolitado:Box.new('ENV_KEY')
|
67
|
+
box.file_encrypt('file_name')
|
68
|
+
box.file_decrypt('encrypt_file_name')
|
69
|
+
````
|
data/lib/.DS_Store
ADDED
Binary file
|
data/lib/lolitado/api.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
module Lolitado
|
3
|
+
class API
|
4
|
+
include HTTParty
|
5
|
+
|
6
|
+
#
|
7
|
+
# format api response
|
8
|
+
#
|
9
|
+
# @param response [String] api response
|
10
|
+
# @param msecs [Float] benchmark for api response time
|
11
|
+
#
|
12
|
+
def self.format_response response, msecs
|
13
|
+
return {:response => response, :message => response.parsed_response, :status => response.code, :duration => msecs}
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# define a customize http request method for rest api, forward this method to call HTTParty.get or HTTParty.post or HTTParty.put
|
18
|
+
# or HTTParty.delete method
|
19
|
+
#
|
20
|
+
# @param method [String] http request method
|
21
|
+
# @param endpoint [String] http request endpoint
|
22
|
+
# @param body [String] http request body
|
23
|
+
#
|
24
|
+
def self.request method, endpoint, body = false
|
25
|
+
start = Time.now
|
26
|
+
case method.to_s
|
27
|
+
when "get"
|
28
|
+
response = self.get(endpoint, :body => body, :headers => API.new_headers, :verify => false)
|
29
|
+
when "post"
|
30
|
+
response = self.post(endpoint, :body => body, :headers => API.new_headers, :verify => false)
|
31
|
+
when "put"
|
32
|
+
response = self.put(endpoint, :body => body, :headers => API.new_headers, :verify => false)
|
33
|
+
when "delete"
|
34
|
+
response = self.delete(endpoint, :headers => API.new_headers, :verify => false)
|
35
|
+
else
|
36
|
+
warn "#{method} is invalid http method."
|
37
|
+
end
|
38
|
+
finish = Time.now
|
39
|
+
msecs = (finish - start) * 1000.0
|
40
|
+
# puts "RESPONSE - #{msecs}"
|
41
|
+
return self.format_response(response, msecs)
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# define a method to set http headers
|
46
|
+
#
|
47
|
+
# @param value [Hash] http header value
|
48
|
+
#
|
49
|
+
def self.add_headers value
|
50
|
+
@new_headers ||= {}
|
51
|
+
@new_headers = @new_headers.merge(value.to_hash)
|
52
|
+
return @new_headers
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# define a method to get http headers
|
57
|
+
#
|
58
|
+
def self.new_headers
|
59
|
+
return @new_headers
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class Graph < API
|
64
|
+
|
65
|
+
#
|
66
|
+
#
|
67
|
+
# define a customize http request method for graph api, forward this method to call HTTParty.get or HTTParty.post or HTTParty.put
|
68
|
+
# or HTTParty.delete method
|
69
|
+
#
|
70
|
+
# @param query [String] graph query
|
71
|
+
# @param variables [String] input variables for graph query using
|
72
|
+
#
|
73
|
+
def self.request query, variables = false
|
74
|
+
super(:post, '/', generate_body(query, variables))
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# format api response, override the parent method in API class
|
79
|
+
#
|
80
|
+
# @param response [String] api response
|
81
|
+
# @param msecs [Float] benchmark for api response time
|
82
|
+
#
|
83
|
+
def self.format_response response, msecs
|
84
|
+
if response.parsed_response.is_a?(Hash)
|
85
|
+
if response.parsed_response.has_key?('errors')
|
86
|
+
message = response.parsed_response
|
87
|
+
else
|
88
|
+
message = response.parsed_response['data'].values[0]
|
89
|
+
end
|
90
|
+
else
|
91
|
+
message = {'errors'=>response.parsed_response}
|
92
|
+
end
|
93
|
+
return {:response => response, :message => message, :status => response.code, :duration => msecs}
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# generate http request body for graph api response
|
98
|
+
#
|
99
|
+
# @param query [String] graph query
|
100
|
+
# @param variables [String] input variables for graph query using
|
101
|
+
#
|
102
|
+
def self.generate_body query, variables
|
103
|
+
body = {}
|
104
|
+
body['query'] = query
|
105
|
+
if variables
|
106
|
+
if query.include?('$input')
|
107
|
+
body['variables'] = {'input'=>variables}
|
108
|
+
else
|
109
|
+
body['variables'] = variables
|
110
|
+
end
|
111
|
+
end
|
112
|
+
body['operationName'] = query.split(' ')[1].split('(')[0]
|
113
|
+
return body.to_json
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
data/lib/lolitado/box.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rbnacl'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module Lolitado
|
5
|
+
class Box
|
6
|
+
|
7
|
+
attr_accessor :box
|
8
|
+
|
9
|
+
#
|
10
|
+
# initialize box
|
11
|
+
#
|
12
|
+
# @param key [String] ENV key value used for initialize box
|
13
|
+
#
|
14
|
+
def initialize key
|
15
|
+
fail "There's no environment variable #{key}..." if ENV[key].nil?
|
16
|
+
key = Base64.decode64(ENV[key])
|
17
|
+
@box = RbNaCl::SimpleBox.from_secret_key(key)
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# encrypt file
|
22
|
+
#
|
23
|
+
# @param file [String] the file need to be encrypted
|
24
|
+
#
|
25
|
+
def file_encrypt file
|
26
|
+
plaintext = File.read(file)
|
27
|
+
ciphertext = box.encrypt(plaintext)
|
28
|
+
enc_file = file + '.enc'
|
29
|
+
File.write(enc_file, Base64.encode64(ciphertext))
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# decrypt file
|
34
|
+
#
|
35
|
+
# @param file [String] the file need to be decrypted
|
36
|
+
#
|
37
|
+
def file_decrypt file
|
38
|
+
ciphertext = File.read(file)
|
39
|
+
plaintext = box.decrypt(Base64.decode64(ciphertext))
|
40
|
+
plain_file = file[0..-5]
|
41
|
+
File.write(plain_file, plaintext)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/lolitado/db.rb
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
module Lolitado
|
2
|
+
class Database
|
3
|
+
|
4
|
+
attr_accessor :db
|
5
|
+
|
6
|
+
def initialize db
|
7
|
+
@db = db
|
8
|
+
end
|
9
|
+
|
10
|
+
#
|
11
|
+
# Return the data by sql.
|
12
|
+
#
|
13
|
+
# @param [String] sql the sql you wanna query
|
14
|
+
#
|
15
|
+
def query sql
|
16
|
+
result = db[sql].all
|
17
|
+
return result
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Return the data by sql.
|
22
|
+
#
|
23
|
+
# @param [String] sql the sql you wanna query, the multiple sql should be split by ;
|
24
|
+
#
|
25
|
+
def multiple_query sql
|
26
|
+
splited_sql = sql.split(';')
|
27
|
+
splited_sql.each do |each_sql|
|
28
|
+
query(each_sql)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Return the data and execute duration by sql.
|
34
|
+
#
|
35
|
+
# @param [String] sql the sql you wanna query
|
36
|
+
# @param [Boolean] type the default value is true that the expected result is not empty, otherwise, the expected result is empty
|
37
|
+
# @param [Number] waiting_time the default value is 10 that maxium execute duration is 10 second
|
38
|
+
#
|
39
|
+
def query_duration sql, type = true, waiting_time = 10
|
40
|
+
start = Time.now
|
41
|
+
if type
|
42
|
+
result = query_wait(sql, waiting_time)
|
43
|
+
else
|
44
|
+
result = query_empty(sql, waiting_time)
|
45
|
+
end
|
46
|
+
finish = Time.now
|
47
|
+
msecs = (finish - start) * 1000.0
|
48
|
+
hash = {'result' => result, 'duration' => msecs}
|
49
|
+
return hash
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Expect to return data for the query. If the result is empty then it will be called again until waiting_time reach.
|
54
|
+
#
|
55
|
+
# @param [String] sql the sql you wanna query
|
56
|
+
# @param [Number] waiting_time the default value is 10 that maxium execute duration is 10 second
|
57
|
+
#
|
58
|
+
def query_wait sql, waiting_time = 10
|
59
|
+
result = db[sql].all
|
60
|
+
if result.empty?
|
61
|
+
if waiting_time != 0
|
62
|
+
sleep 1
|
63
|
+
result = query_wait(sql, waiting_time - 1)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
return result
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Expect to return empty for the query. If the result is not empty then it will be called again until waiting_time reach.
|
71
|
+
#
|
72
|
+
# @param [String] sql the sql you wanna query
|
73
|
+
# @param [Number] waiting_time the default value is 10 that maxium execute duration is 10 second
|
74
|
+
#
|
75
|
+
def query_empty sql, waiting_time = 10
|
76
|
+
result = db[sql].all
|
77
|
+
if !result.empty?
|
78
|
+
if waiting_time != 0
|
79
|
+
sleep 1
|
80
|
+
result = query(sql, waiting_time - 1)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
return result
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Execute by sql, the sql is normally update or insert.
|
88
|
+
#
|
89
|
+
# @param [String] sql the sql you wanna execute
|
90
|
+
#
|
91
|
+
def execute sql
|
92
|
+
db[sql]
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# Insert data by data.
|
97
|
+
#
|
98
|
+
# @param [String] data the data wanna insert which is array or hash
|
99
|
+
# @param [String] table the table wanna insert
|
100
|
+
#
|
101
|
+
def insert_by_data data, table
|
102
|
+
sql = "insert into #{table} "
|
103
|
+
case data
|
104
|
+
when Array
|
105
|
+
data.each do |d|
|
106
|
+
insert_by_data(d, table)
|
107
|
+
end
|
108
|
+
when Hash
|
109
|
+
columns = data.keys.to_s.gsub('[','(').gsub(']',')').gsub('"','')
|
110
|
+
values = data.values.to_s.gsub('[','(').gsub(']',')').gsub('nil','NULL')
|
111
|
+
sql = sql + columns + " values " + values
|
112
|
+
query(sql)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
#
|
117
|
+
# Update data by data.
|
118
|
+
#
|
119
|
+
# @param [Hash] data the data wanna update which is hash
|
120
|
+
# @param [String] table the table for the update
|
121
|
+
# @param [Hash] condition the condition for the update
|
122
|
+
#
|
123
|
+
def update data, table, condition = {}
|
124
|
+
sql = "update #{table} set"
|
125
|
+
data.each do |k,v|
|
126
|
+
v = v.to_json if v.is_a?(Hash)
|
127
|
+
if !!v == v
|
128
|
+
sql = "#{sql} #{k}=#{v},"
|
129
|
+
else
|
130
|
+
sql = "#{sql} #{k}='#{v}',"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
sql = sql[0..-2] + " where"
|
134
|
+
condition.each do |k,v|
|
135
|
+
sql = "#{sql} #{k} = '#{v}' and"
|
136
|
+
end
|
137
|
+
query(sql[0..-4])
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'mysql2'
|
2
|
+
require 'sequel'
|
3
|
+
require 'net/ssh/gateway'
|
4
|
+
require 'psych'
|
5
|
+
require_relative 'db'
|
6
|
+
|
7
|
+
module Lolitado
|
8
|
+
class Pool
|
9
|
+
|
10
|
+
attr_accessor :db_pool, :ssh_pool, :file
|
11
|
+
|
12
|
+
#
|
13
|
+
# initialize Lolitado::Pool, generate db_pool, ssh_pool object to use
|
14
|
+
#
|
15
|
+
# @param file_path [String] the configure file to used for initialize
|
16
|
+
#
|
17
|
+
def initialize file_path
|
18
|
+
@db_pool = {}
|
19
|
+
@ssh_pool = {}
|
20
|
+
@file = Psych.load_file(file_path)
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# use existing db or ssh pool or switch to another db and ssh pool
|
25
|
+
#
|
26
|
+
# @param params [Hash] key, value used to use db/ssh pool
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# pool.use(:db => 'db_name')
|
30
|
+
#
|
31
|
+
def use(params = {})
|
32
|
+
ssh_name = params.fetch(:ssh, false)
|
33
|
+
db_name = params.fetch(:db, false)
|
34
|
+
if db_name
|
35
|
+
return get_db db_name
|
36
|
+
elsif ssh_name
|
37
|
+
return get_ssh ssh_name
|
38
|
+
else
|
39
|
+
fail "Please provide :ssh or :db"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# return existing db object or create new db object
|
45
|
+
#
|
46
|
+
# @param name [String] db configure name in yaml file
|
47
|
+
#
|
48
|
+
def get_db name
|
49
|
+
if db_pool[name].nil?
|
50
|
+
db_conf = file[name]
|
51
|
+
if db_conf['proxy'].nil?
|
52
|
+
db = connect_database db_conf
|
53
|
+
else
|
54
|
+
db = connect_database_by_proxy db_conf
|
55
|
+
end
|
56
|
+
db_pool[name] = Database.new(db)
|
57
|
+
end
|
58
|
+
return db_pool[name]
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# return existing ssh object or create new ssh object
|
63
|
+
#
|
64
|
+
# @param name [String] ssh configure name in yaml file
|
65
|
+
#
|
66
|
+
def get_ssh name
|
67
|
+
if ssh_pool[name].nil?
|
68
|
+
ssh = connect_remote_server name
|
69
|
+
ssh_pool[name] = ssh
|
70
|
+
else
|
71
|
+
ssh_pool[name]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# connect database by ssh proxy
|
77
|
+
#
|
78
|
+
# @param conf [Hash] configuration for connect remote databse via ssh
|
79
|
+
#
|
80
|
+
def connect_database_by_proxy conf
|
81
|
+
port = forward_port conf['proxy']
|
82
|
+
connect_database conf, port
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# connect databse
|
87
|
+
#
|
88
|
+
# @param conf [Hash] configuration for connect databse directly
|
89
|
+
# @pram port [Integer] forward port
|
90
|
+
#
|
91
|
+
def connect_database conf, port = false
|
92
|
+
conf.delete('proxy') if port
|
93
|
+
conf = conf.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
94
|
+
conf = conf.merge(:port => port) if port
|
95
|
+
begin
|
96
|
+
Sequel.connect(conf)
|
97
|
+
rescue
|
98
|
+
fail "database configuration \n #{conf} \n is not correct, please double check"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# connect remote server
|
104
|
+
#
|
105
|
+
# @param name [String] the ssh server name wanna to connect
|
106
|
+
#
|
107
|
+
def connect_remote_server name
|
108
|
+
ssh_conf = file[name]
|
109
|
+
host = ssh_conf.delete('host')
|
110
|
+
user = ssh_conf.delete('user')
|
111
|
+
options = ssh_conf.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
112
|
+
begin
|
113
|
+
Net::SSH::Gateway.new(host, user, options)
|
114
|
+
rescue
|
115
|
+
fail "ssh configuration \n #{ssh_conf} \n is not correct, please double check"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
# forward port
|
121
|
+
#
|
122
|
+
# @param conf [Hash] configuration for generate forward port
|
123
|
+
#
|
124
|
+
def forward_port conf
|
125
|
+
ssh = get_ssh conf['ssh']
|
126
|
+
host = conf['database']['host']
|
127
|
+
remote_port = conf['database']['remote_port']
|
128
|
+
local_port = conf['database']['local_port']
|
129
|
+
# puts "forward remote port #{remote_port} to local port #{local_port}"
|
130
|
+
begin
|
131
|
+
ssh.open(host, remote_port, local_port)
|
132
|
+
rescue Errno::EADDRINUSE
|
133
|
+
return local_port
|
134
|
+
rescue
|
135
|
+
fail "fail to forward remote port #{remote_port} to local_port #{local_port}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
data/lib/lolitado.rb
CHANGED
@@ -1,10 +1,82 @@
|
|
1
|
-
|
2
|
-
require 'db'
|
3
|
-
require 'request'
|
4
|
-
require 'box'
|
1
|
+
$:.unshift File.expand_path('..', __FILE__)
|
5
2
|
|
6
|
-
|
7
|
-
|
3
|
+
require 'lolitado/pool'
|
4
|
+
require 'lolitado/db'
|
5
|
+
require 'lolitado/api'
|
6
|
+
require 'lolitado/box'
|
8
7
|
|
8
|
+
#
|
9
|
+
# Module that when included adds functionality to an API(Rest/Graph) Class.
|
10
|
+
#
|
11
|
+
# How to use it ?
|
12
|
+
#
|
13
|
+
# @example Rest API
|
14
|
+
# class TestRest
|
15
|
+
# include Lolitado
|
16
|
+
|
17
|
+
# def initialize
|
18
|
+
# base_uri 'https://xxx.com'
|
19
|
+
# end
|
20
|
+
|
21
|
+
# def get_details_of_a_city city_slug, locale
|
22
|
+
# add_headers({'Accept-Language' => locale})
|
23
|
+
# request('get', "/cities/#{city_slug}")
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# @example Graph API
|
28
|
+
# class TestGraph
|
29
|
+
# include Lolitado
|
30
|
+
|
31
|
+
# def initialize
|
32
|
+
# base_uri 'https://xxx.com'
|
33
|
+
# end
|
34
|
+
|
35
|
+
# def user_login payload
|
36
|
+
# add_headers({'Content-Type' => "application/json"})
|
37
|
+
# query = "mutation login($input: UserLoginInput!) {userLogin(input:$input) {authToken}}"
|
38
|
+
# graph_request(query, payload)
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
module Lolitado
|
42
|
+
|
43
|
+
#
|
44
|
+
# forward request method from Rest class to API.request method
|
45
|
+
#
|
46
|
+
# @param method [String] http request method
|
47
|
+
# @param endpoint [String] http request endpoint
|
48
|
+
# @param body [String] http request body
|
49
|
+
#
|
50
|
+
def request method, endpoint, body=false
|
51
|
+
API.request(method, endpoint, body)
|
9
52
|
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# forward graph_request method from Graph class to Graph.request method
|
56
|
+
#
|
57
|
+
# @param query [String] graph query
|
58
|
+
# @param variables [String] input variables for graph query using
|
59
|
+
#
|
60
|
+
def graph_request query, variables = false
|
61
|
+
Graph.request(query, variables)
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# forward add_headers from Rest/Graph class to API.add_headers method
|
66
|
+
#
|
67
|
+
# @param value [Hash] http header value
|
68
|
+
#
|
69
|
+
def add_headers value
|
70
|
+
API.add_headers value
|
71
|
+
end
|
72
|
+
|
73
|
+
#
|
74
|
+
# forward uri from Rest/Graph class to API.uri method
|
75
|
+
#
|
76
|
+
# @param uri [String] http request uri
|
77
|
+
#
|
78
|
+
def base_uri uri
|
79
|
+
API.base_uri uri
|
80
|
+
end
|
81
|
+
|
10
82
|
end
|
data/lolitado.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "lolitado/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "lolitado"
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.version = Lolitado::VERSION
|
9
|
+
s.date = '2018-12-14'
|
10
|
+
s.authors = ["Dolores Zhang"]
|
11
|
+
s.email = ["379808610@qq.com"]
|
12
|
+
s.homepage = "http://github.com/doloreszhang/lolitado"
|
13
|
+
s.summary = %q{Lolitado DSL for database process}
|
14
|
+
s.description = %q{Lolitado DSL that works with Watir}
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.license = 'MIT'
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.add_dependency "sequel", "~> 4.37"
|
19
|
+
s.add_dependency "net-ssh-gateway", "~> 1.2"
|
20
|
+
s.add_dependency "httparty", "~> 0.14"
|
21
|
+
s.add_dependency "rbnacl-libsodium", "~> 1.0.10"
|
22
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lolitado
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dolores Zhang
|
@@ -73,13 +73,17 @@ executables: []
|
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
75
75
|
files:
|
76
|
-
-
|
77
|
-
-
|
78
|
-
-
|
76
|
+
- ".DS_Store"
|
77
|
+
- ".gitignore"
|
78
|
+
- README.md
|
79
|
+
- lib/.DS_Store
|
79
80
|
- lib/lolitado.rb
|
80
|
-
- lib/
|
81
|
-
- lib/
|
82
|
-
- lib/
|
81
|
+
- lib/lolitado/api.rb
|
82
|
+
- lib/lolitado/box.rb
|
83
|
+
- lib/lolitado/db.rb
|
84
|
+
- lib/lolitado/pool.rb
|
85
|
+
- lib/lolitado/version.rb
|
86
|
+
- lolitado.gemspec
|
83
87
|
homepage: http://github.com/doloreszhang/lolitado
|
84
88
|
licenses:
|
85
89
|
- MIT
|
@@ -100,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
104
|
version: '0'
|
101
105
|
requirements: []
|
102
106
|
rubyforge_project:
|
103
|
-
rubygems_version: 2.7.
|
107
|
+
rubygems_version: 2.7.7
|
104
108
|
signing_key:
|
105
109
|
specification_version: 4
|
106
110
|
summary: Lolitado DSL for database process
|
data/lib/accessors.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Contains the class level methods that are inserted into your api class
|
3
|
-
#
|
4
|
-
module Accessors
|
5
|
-
|
6
|
-
# just for example "how to create method in accesors"
|
7
|
-
def row name, identifier
|
8
|
-
define_method("delete_#{name}") do |value|
|
9
|
-
db[identifier[:table].to_sym].filter(value).delete
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def column name, identifier
|
14
|
-
define_method("avg_#{name}") do |value|
|
15
|
-
db[identifier[:table].to_sym].filter(value).avg(identifier.values.last.to_sym)
|
16
|
-
end
|
17
|
-
define_method("query_#{name}") do |value|
|
18
|
-
db[identifier[:table].to_sym].filter(value).all
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
data/lib/box.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'rbnacl'
|
2
|
-
require 'base64'
|
3
|
-
|
4
|
-
class Box
|
5
|
-
|
6
|
-
def initialize key
|
7
|
-
key_env = ENV[key]
|
8
|
-
if key_env.nil?
|
9
|
-
puts "There's no environment variable #{key}..."
|
10
|
-
return
|
11
|
-
end
|
12
|
-
key = Base64.decode64(key_env)
|
13
|
-
@box = RbNaCl::SimpleBox.from_secret_key(key)
|
14
|
-
end
|
15
|
-
|
16
|
-
def file_encrypt file
|
17
|
-
plaintext = File.read(file)
|
18
|
-
ciphertext = @box.encrypt(plaintext)
|
19
|
-
enc_file = file + '.enc'
|
20
|
-
File.write(enc_file, Base64.encode64(ciphertext))
|
21
|
-
end
|
22
|
-
|
23
|
-
def file_decrypt file
|
24
|
-
ciphertext = File.read(file)
|
25
|
-
plaintext = @box.decrypt(Base64.decode64(ciphertext))
|
26
|
-
plain_file = file[0..-5]
|
27
|
-
File.write(plain_file, plaintext)
|
28
|
-
end
|
29
|
-
end
|
data/lib/db.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'accessors'
|
2
|
-
|
3
|
-
class DBFactory
|
4
|
-
extend Accessors
|
5
|
-
|
6
|
-
attr_accessor :db
|
7
|
-
|
8
|
-
def initialize db
|
9
|
-
@db = db
|
10
|
-
end
|
11
|
-
|
12
|
-
def query sql
|
13
|
-
result = db[sql].all
|
14
|
-
return result
|
15
|
-
end
|
16
|
-
|
17
|
-
def multiple_query sql
|
18
|
-
splited_sql = sql.split(';')
|
19
|
-
splited_sql.each do |each_sql|
|
20
|
-
query(each_sql)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def insert sql
|
25
|
-
db[sql]
|
26
|
-
end
|
27
|
-
end
|
data/lib/pool.rb
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
require 'mysql2'
|
2
|
-
require 'sequel'
|
3
|
-
require 'net/ssh/gateway'
|
4
|
-
|
5
|
-
class Pool
|
6
|
-
|
7
|
-
attr_accessor :db_pool, :ssh_pool, :file_path
|
8
|
-
|
9
|
-
def initialize file_path
|
10
|
-
@db_pool = {}
|
11
|
-
@ssh_pool = {}
|
12
|
-
@file_path = file_path
|
13
|
-
end
|
14
|
-
|
15
|
-
def use(params ={})
|
16
|
-
ssh_name = params.fetch(:ssh, false)
|
17
|
-
db_name = params.fetch(:db, false)
|
18
|
-
if db_pool[db_name].nil? && db_name
|
19
|
-
ssh_key = fetch_ssh_config db_name
|
20
|
-
unless ssh_key.nil?
|
21
|
-
ssh = create_or_use_ssh ssh_key
|
22
|
-
port = forward_port ssh, ssh_key
|
23
|
-
db = connect_database db_name, port
|
24
|
-
db_pool[db_name] = db
|
25
|
-
else
|
26
|
-
db = connect_database_directly db_name
|
27
|
-
db_pool[db_name] = db
|
28
|
-
end
|
29
|
-
elsif ssh_name
|
30
|
-
create_or_use_ssh ssh_name
|
31
|
-
else
|
32
|
-
db_pool[db_name]
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def create_or_use_ssh name
|
37
|
-
if ssh_pool[name].nil?
|
38
|
-
ssh = connect_remote_server name
|
39
|
-
ssh_pool[name] = ssh
|
40
|
-
else
|
41
|
-
ssh_pool[name]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def connect_database name, port=false
|
46
|
-
database_file = YAML.load_file(file_path)
|
47
|
-
db_conf = database_file[name]
|
48
|
-
db_conf = db_conf.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
49
|
-
db_conf = db_conf.merge(:port => port) if port
|
50
|
-
db = get_ready_for_database db_conf
|
51
|
-
end
|
52
|
-
|
53
|
-
def get_ready_for_database conf
|
54
|
-
begin
|
55
|
-
Sequel.connect(conf)
|
56
|
-
rescue
|
57
|
-
fail "database configuration \n #{conf} \n is not correct, please double check"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def connect_remote_server name
|
62
|
-
database_file = YAML.load_file(file_path)
|
63
|
-
ssh_conf = database_file[name]
|
64
|
-
ssh_conf = ssh_conf.delete_if { |key,value| key == 'database'}
|
65
|
-
ssh = get_ready_for_ssh ssh_conf
|
66
|
-
return ssh
|
67
|
-
end
|
68
|
-
|
69
|
-
def get_ready_for_ssh conf
|
70
|
-
host = conf.delete('host')
|
71
|
-
user = conf.delete('user')
|
72
|
-
options = conf.delete_if {|key,value| key == 'host' && 'user'}
|
73
|
-
options = options.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
74
|
-
begin
|
75
|
-
Net::SSH::Gateway.new(host, user, options)
|
76
|
-
rescue
|
77
|
-
fail "ssh configuration \n #{conf} \n is not correct, please double check"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def forward_port ssh, name
|
82
|
-
database_file = YAML.load_file(file_path)
|
83
|
-
ssh_conf = database_file[name]
|
84
|
-
new_conf = ssh_conf.delete('database')
|
85
|
-
host = new_conf.delete('host')
|
86
|
-
remote_port = new_conf.delete('remote_port')
|
87
|
-
local_port = new_conf.delete('local_port')
|
88
|
-
begin
|
89
|
-
ssh.open(host, remote_port, local_port)
|
90
|
-
rescue Errno::EADDRINUSE
|
91
|
-
return local_port
|
92
|
-
rescue
|
93
|
-
fail "fail to forward remote port #{remote_port} to local_port #{local_port}"
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def fetch_ssh_config db_name
|
98
|
-
database_file = YAML.load_file(file_path)
|
99
|
-
db_conf = database_file[db_name]
|
100
|
-
ssh_key = db_conf.delete('ssh')
|
101
|
-
end
|
102
|
-
|
103
|
-
def connect_database_directly db_name
|
104
|
-
database_file = YAML.load_file(file_path)
|
105
|
-
db_conf = database_file[db_name]
|
106
|
-
db_conf = db_conf.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
107
|
-
db = Sequel.connect(db_conf)
|
108
|
-
end
|
109
|
-
end
|
data/lib/request.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'httparty'
|
2
|
-
|
3
|
-
class Request
|
4
|
-
include HTTParty
|
5
|
-
|
6
|
-
attr_accessor :new_headers
|
7
|
-
# debug_output $stdout
|
8
|
-
|
9
|
-
def new_response response, msecs
|
10
|
-
new_response = {}
|
11
|
-
new_response.merge({:response => response, :message => response.parsed_response, :status => response.code, :duration => msecs})
|
12
|
-
end
|
13
|
-
|
14
|
-
def request base_uri, method, endpoint, body = false
|
15
|
-
url = base_uri + endpoint
|
16
|
-
case method
|
17
|
-
when "get"
|
18
|
-
start = Time.now
|
19
|
-
response = self.class.get(url, :body => body, :headers => new_headers, :verify => false)
|
20
|
-
finish = Time.now
|
21
|
-
when "post"
|
22
|
-
start = Time.now
|
23
|
-
response = self.class.post(url, :body => body, :headers => new_headers, :verify => false)
|
24
|
-
finish = Time.now
|
25
|
-
when "put"
|
26
|
-
start = Time.now
|
27
|
-
response = self.class.put(url, :body => body, :headers => new_headers, :verify => false)
|
28
|
-
finish = Time.now
|
29
|
-
when "delete"
|
30
|
-
start = Time.now
|
31
|
-
response = self.class.delete(url, :headers => new_headers, :verify => false)
|
32
|
-
finish = Time.now
|
33
|
-
else
|
34
|
-
puts "#{method} is invalid method."
|
35
|
-
exit
|
36
|
-
end
|
37
|
-
msecs = (finish - start) * 1000.0
|
38
|
-
return new_response(response, msecs)
|
39
|
-
end
|
40
|
-
|
41
|
-
def add_headers value
|
42
|
-
@new_headers ||= {}
|
43
|
-
@new_headers = @new_headers.merge(value.to_hash)
|
44
|
-
return @new_headers
|
45
|
-
end
|
46
|
-
end
|