syncano 3.1.4 → 4.0.0.alpha

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.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -1
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +3 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +25 -1
  7. data/Guardfile +22 -4
  8. data/README.md +68 -447
  9. data/Rakefile +48 -5
  10. data/circle.yml +10 -0
  11. data/lib/active_attr/dirty.rb +3 -17
  12. data/lib/active_attr/typecasting/hash_typecaster.rb +34 -0
  13. data/lib/active_attr/typecasting_override.rb +29 -0
  14. data/lib/syncano.rb +53 -92
  15. data/lib/syncano/api.rb +13 -0
  16. data/lib/syncano/connection.rb +97 -0
  17. data/lib/syncano/model/associations.rb +121 -0
  18. data/lib/syncano/{active_record/association → model/associations}/base.rb +5 -5
  19. data/lib/syncano/{active_record/association → model/associations}/belongs_to.rb +6 -6
  20. data/lib/syncano/{active_record/association → model/associations}/has_many.rb +15 -9
  21. data/lib/syncano/{active_record/association → model/associations}/has_one.rb +4 -4
  22. data/lib/syncano/model/base.rb +257 -0
  23. data/lib/syncano/{active_record → model}/callbacks.rb +16 -13
  24. data/lib/syncano/{active_record → model}/scope_builder.rb +53 -69
  25. data/lib/syncano/query_builder.rb +19 -129
  26. data/lib/syncano/resources.rb +126 -0
  27. data/lib/syncano/resources/base.rb +304 -300
  28. data/lib/syncano/resources/collection.rb +19 -223
  29. data/lib/syncano/resources/space.rb +29 -0
  30. data/lib/syncano/schema.rb +86 -0
  31. data/lib/syncano/schema/attribute_definition.rb +83 -0
  32. data/lib/syncano/schema/resource_definition.rb +36 -0
  33. data/lib/syncano/scope.rb +10 -0
  34. data/lib/syncano/version.rb +3 -4
  35. data/spec/integration/syncano_spec.rb +228 -0
  36. data/spec/spec_helper.rb +15 -9
  37. data/spec/unit/api_spec.rb +5 -0
  38. data/spec/unit/connection_spec.rb +137 -0
  39. data/spec/unit/query_builder_spec.rb +75 -0
  40. data/spec/unit/resources/collection_spec.rb +36 -0
  41. data/spec/unit/resources/space_spec.rb +28 -0
  42. data/spec/unit/resources_base_spec.rb +185 -0
  43. data/spec/unit/schema/attribute_definition_spec.rb +18 -0
  44. data/spec/unit/schema/resource_definition_spec.rb +25 -0
  45. data/spec/unit/schema_spec.rb +3532 -0
  46. data/spec/unit/syncano_spec.rb +63 -0
  47. data/syncano.gemspec +8 -14
  48. metadata +85 -210
  49. data/lib/generators/syncano/install_generator.rb +0 -17
  50. data/lib/generators/syncano/templates/initializers/syncano.rb +0 -7
  51. data/lib/syncano/active_record/associations.rb +0 -112
  52. data/lib/syncano/active_record/base.rb +0 -318
  53. data/lib/syncano/batch_queue.rb +0 -58
  54. data/lib/syncano/batch_queue_element.rb +0 -33
  55. data/lib/syncano/clients/base.rb +0 -123
  56. data/lib/syncano/clients/rest.rb +0 -79
  57. data/lib/syncano/clients/sync.rb +0 -164
  58. data/lib/syncano/errors.rb +0 -17
  59. data/lib/syncano/jimson_client.rb +0 -66
  60. data/lib/syncano/packets/auth.rb +0 -27
  61. data/lib/syncano/packets/base.rb +0 -70
  62. data/lib/syncano/packets/call.rb +0 -34
  63. data/lib/syncano/packets/call_response.rb +0 -33
  64. data/lib/syncano/packets/error.rb +0 -19
  65. data/lib/syncano/packets/message.rb +0 -30
  66. data/lib/syncano/packets/notification.rb +0 -39
  67. data/lib/syncano/packets/ping.rb +0 -12
  68. data/lib/syncano/resources/admin.rb +0 -26
  69. data/lib/syncano/resources/api_key.rb +0 -108
  70. data/lib/syncano/resources/data_object.rb +0 -316
  71. data/lib/syncano/resources/folder.rb +0 -88
  72. data/lib/syncano/resources/notifications/base.rb +0 -103
  73. data/lib/syncano/resources/notifications/create.rb +0 -20
  74. data/lib/syncano/resources/notifications/destroy.rb +0 -20
  75. data/lib/syncano/resources/notifications/message.rb +0 -9
  76. data/lib/syncano/resources/notifications/update.rb +0 -24
  77. data/lib/syncano/resources/project.rb +0 -96
  78. data/lib/syncano/resources/role.rb +0 -11
  79. data/lib/syncano/resources/subscription.rb +0 -12
  80. data/lib/syncano/resources/user.rb +0 -65
  81. data/lib/syncano/response.rb +0 -22
  82. data/lib/syncano/sync_connection.rb +0 -133
  83. data/spec/admins_spec.rb +0 -16
  84. data/spec/api_keys_spec.rb +0 -34
  85. data/spec/collections_spec.rb +0 -67
  86. data/spec/data_objects_spec.rb +0 -113
  87. data/spec/folders_spec.rb +0 -39
  88. data/spec/notifications_spec.rb +0 -43
  89. data/spec/projects_spec.rb +0 -35
  90. data/spec/roles_spec.rb +0 -13
  91. data/spec/sync_resources_spec.rb +0 -35
  92. data/spec/syncano_spec.rb +0 -9
@@ -1,58 +0,0 @@
1
- class Syncano
2
- # Class representing queues used in batch requests
3
- class BatchQueue
4
- # Limit for amount of batch operations send in one request
5
- REQUEST_LIMIT = 10
6
- attr_reader :responses
7
-
8
- # Constructor for Syncano::BatchQueue
9
- # @param [Syncano::Clients::Base] client
10
- def initialize(client)
11
- super()
12
- self.client = client
13
- self.queue = []
14
- self.responses = []
15
- end
16
-
17
- # Adds element to the queue and prune it if is full
18
- # @param [Syncano::BatchQueueElement] element
19
- def add(element)
20
- self.queue << element
21
- prune! while full?
22
- end
23
-
24
- # Alias for "add" method
25
- # @param [Syncano::BatchQueueElement] element
26
- def <<(element)
27
- add(element)
28
- end
29
-
30
- # Counts elements in the queue
31
- # @return [Integer]
32
- def count
33
- queue.count
34
- end
35
-
36
- # Checks if queue is full
37
- # @return [TrueClass, FalseClass]
38
- def full?
39
- count >= REQUEST_LIMIT
40
- end
41
-
42
- # Prunes queue and makes batch request to the api
43
- # @return [Array] collection of Syncano::Response objects
44
- def prune!
45
- part = self.queue.slice!(0, 10)
46
- ::Jimson::Client.batch(client) do |batch_client|
47
- part.each do |element|
48
- element.perform!(batch_client)
49
- end
50
- end.collect { |response| self.responses << response }
51
- end
52
-
53
- protected
54
-
55
- attr_accessor :client, :queue
56
- attr_writer :responses
57
- end
58
- end
@@ -1,33 +0,0 @@
1
- class Syncano
2
- # Class representing objects batch requests queued for processing
3
- class BatchQueueElement
4
- # Constructor for Syncano::BatchQueueElement
5
- # @param [Syncano::QueryBuilder, Syncano::Resources::Base] resource
6
- def initialize(resource)
7
- super()
8
- self.resource = resource.dup
9
- end
10
-
11
- # Overwritten method_missing used for preparing execution of proper batch method on the resource object
12
- # @param [Symbol] sym
13
- # @param [Array] args
14
- # @param [Proc] block
15
- # @return [Syncano::BatchQueueElement]
16
- def method_missing(sym, *args, &block)
17
- self.method_name = 'batch_' + sym.to_s
18
- self.args = args
19
- self.block = block
20
- self
21
- end
22
-
23
- # Executes batch method on the resource object
24
- def perform!(batch_client)
25
- args.unshift(batch_client)
26
- resource.send(method_name, *args, &block)
27
- end
28
-
29
- private
30
-
31
- attr_accessor :resource, :method_name, :args, :block
32
- end
33
- end
@@ -1,123 +0,0 @@
1
- class Syncano
2
- # Module used as a scope for classes representing clients
3
- module Clients
4
- # Base class for representing clients
5
- class Base
6
- attr_reader :instance_name, :api_key, :auth_key
7
-
8
- # Constructor for Syncano::Clients::Base object
9
- # @param [String] instance_name
10
- # @param [String] api_key
11
- def initialize(instance_name, api_key, auth_key)
12
- super()
13
-
14
- self.instance_name = instance_name
15
- self.api_key = api_key
16
- self.auth_key = auth_key if auth_key.present?
17
- end
18
-
19
- # Deletes saved auth_key
20
- # @return [TrueClass, FalseClass]
21
- def logout
22
- self.auth_key = nil
23
- self.auth_key.nil?
24
- end
25
-
26
- # Returns query builder for Syncano::Resources::Admin objects
27
- # @return [Syncano::QueryBuilder]
28
- def admins
29
- ::Syncano::QueryBuilder.new(self, ::Syncano::Resources::Admin)
30
- end
31
-
32
- # Returns query builder for Syncano::Resources::ApiKey objects
33
- # @return [Syncano::QueryBuilder]
34
- def api_keys
35
- ::Syncano::QueryBuilder.new(self, ::Syncano::Resources::ApiKey)
36
- end
37
-
38
- # Returns query builder for Syncano::Resources::Role objects
39
- # @return [Syncano::QueryBuilder]
40
- def roles
41
- ::Syncano::QueryBuilder.new(self, ::Syncano::Resources::Role)
42
- end
43
-
44
- # Returns query builder for Syncano::Resources::Project objects
45
- # @return [Syncano::QueryBuilder]
46
- def projects
47
- ::Syncano::QueryBuilder.new(self, ::Syncano::Resources::Project)
48
- end
49
-
50
- # Returns query builder for Syncano::Resources::Project objects
51
- # @param [Integer, String] project_id
52
- # @return [Syncano::QueryBuilder]
53
- def collections(project_id)
54
- ::Syncano::QueryBuilder.new(self, ::Syncano::Resources::Collection, project_id: project_id)
55
- end
56
-
57
- # Returns query builder for Syncano::Resources::Folder objects
58
- # @param [Integer, String] project_id
59
- # @param [Integer, String] collection_id
60
- # @return [Syncano::QueryBuilder]
61
- def folders(project_id, collection_id)
62
- ::Syncano::QueryBuilder.new(self, ::Syncano::Resources::Collection, project_id: project_id, collection_id: collection_id)
63
- end
64
-
65
- # Returns query builder for Syncano::Resources::DataObject objects
66
- # @param [Integer, String] project_id
67
- # @param [Integer, String] collection_id
68
- # @return [Syncano::QueryBuilder]
69
- def data_objects(project_id, collection_id)
70
- ::Syncano::QueryBuilder.new(self, ::Syncano::Resources::DataObject, project_id: project_id, collection_id: collection_id)
71
- end
72
-
73
- # Returns query builder for Syncano::Resources::User objects
74
- # @param [Integer, String] project_id
75
- # @param [Integer, String] collection_id
76
- # @return [Syncano::QueryBuilder]
77
- def users
78
- ::Syncano::QueryBuilder.new(self, ::Syncano::Resources::User)
79
- end
80
-
81
- # Performs request to Syncano api
82
- # This should be overwritten in inherited classes
83
- # @param [String] resource_name
84
- # @param [String] method_name
85
- # @param [Hash] params additional params sent in the request
86
- # @param [String] response_key for cases when response from api is incompatible with the convention
87
- # @return [Syncano::Response]
88
- def make_request(resource_name, method_name, params = {}, response_key = nil)
89
- end
90
-
91
- # Performs batch request to Syncano api
92
- # This should be overwritten in inherited classes
93
- # @param [Jimson::BatchClient] batch_client
94
- # @param [String] resource_name
95
- # @param [String] method_name
96
- # @param [Hash] params additional params sent in the request
97
- def make_batch_request(batch_client, resource_name, method_name, params = {})
98
- end
99
-
100
- private
101
-
102
- attr_writer :instance_name, :api_key, :auth_key
103
-
104
- # Parses Syncano api response and returns Syncano::Response object
105
- # @param [String] response_key
106
- # @param [Hash] raw_response
107
- # @return [Syncano::Response]
108
- def self.parse_response(response_key, raw_response)
109
- status = raw_response.nil? || raw_response['result'] != 'NOK'
110
- if raw_response.nil?
111
- data = nil
112
- elsif raw_response[response_key.to_s].present?
113
- data = raw_response[response_key.to_s]
114
- else
115
- data = raw_response['count']
116
- end
117
- errors = status ? [] : raw_response['error']
118
-
119
- ::Syncano::Response.new(status, data, errors)
120
- end
121
- end
122
- end
123
- end
@@ -1,79 +0,0 @@
1
- class Syncano
2
- module Clients
3
- # Client used for communication with the JSON-RPC endpoint
4
- class Rest < Syncano::Clients::Base
5
- attr_reader :client
6
-
7
- # Constructor for Syncano::Clients::Rest object
8
- # @param [String] instance_name
9
- # @param [String] api_key
10
- def initialize(instance_name, api_key, auth_key = nil)
11
- super(instance_name, api_key, auth_key)
12
- self.client = ::Jimson::Client.new(json_rpc_url)
13
- end
14
-
15
- # Gets auth_key based on username and password
16
- # @return [TrueClass, FalseClass]
17
- def login(username, password)
18
- logout
19
- self.auth_key = users.login(username, password)
20
- !self.auth_key.nil?
21
- end
22
-
23
- # Performs request to Syncano api
24
- # @param [String] resource_name
25
- # @param [String] method_name
26
- # @param [Hash] params additional params sent in the request
27
- # @param [String] response_key for cases when response from api is incompatible with the convention
28
- # @return [Syncano::Response]
29
- def make_request(resource_name, method_name, params = {}, response_key = nil)
30
- params.merge!(auth_key: auth_key) if auth_key.present?
31
-
32
- response_key ||= resource_name
33
- response = client.send("#{resource_name}.#{method_name}", request_params.merge(params))
34
- response = self.class.parse_response(response_key, response)
35
-
36
- response.errors.present? ? raise(Syncano::ApiError.new(response.errors)) : response
37
- end
38
-
39
- # Performs batch request to Syncano api
40
- # @param [Jimson::BatchClient] batch_client
41
- # @param [String] resource_name
42
- # @param [String] method_name
43
- # @param [Hash] params additional params sent in the request
44
- def make_batch_request(batch_client, resource_name, method_name, params = {})
45
- batch_client.send("#{resource_name}.#{method_name}", request_params.merge(params))
46
- end
47
-
48
- # Gets block in which Syncano::BatchQueue object is provided and batch requests can be executed
49
- # @param [Block]
50
- # @return [Array] collection of parsed responses
51
- def batch
52
- queue = ::Syncano::BatchQueue.new(client)
53
- yield(queue)
54
- queue.prune!
55
-
56
- queue.responses.collect do |response|
57
- resource_name = response.first.method.split('.').first
58
- self.class.parse_response(resource_name, response.last.result)
59
- end
60
- end
61
-
62
- private
63
-
64
- attr_writer :client
65
-
66
- # Generates url to json rpc api
67
- # @return [String]
68
- def json_rpc_url
69
- "https://#{instance_name}.syncano.com/api/jsonrpc"
70
- end
71
-
72
- # Prepares hash with default request params
73
- # @return [Hash]
74
- def request_params
75
- { api_key: api_key }
76
- end
77
- end
78
- end
79
- end
@@ -1,164 +0,0 @@
1
- class Syncano
2
- module Clients
3
- # Client used for communication with the Sync Server
4
- class Sync < Syncano::Clients::Base
5
- include ::Singleton
6
-
7
- attr_accessor :connection
8
-
9
- # Constructor for Syncano::Clients::Sync object
10
- # @param [String] instance_name
11
- # @param [String] api_key
12
- def initialize(instance_name, api_key, auth_key = nil)
13
- super(instance_name, api_key, auth_key)
14
- self.connection = nil
15
- self.auth_key = auth_key if auth_key.present?
16
- end
17
-
18
- # Getter for Singleton instance
19
- # @param [String] instance_name
20
- # @param [String] api_key
21
- # @return [Syncano::Clients::Base]
22
- def self.instance(instance_name = nil, api_key = nil, auth_key = nil)
23
- unless @singleton__instance__
24
- @singleton__mutex__.synchronize do
25
- return @singleton__instance__ if @singleton__instance__
26
- @singleton__instance__ = new(instance_name, api_key, auth_key)
27
- end
28
- end
29
- @singleton__instance__
30
- end
31
-
32
- # Checks if client is connected
33
- # @return [TrueClass, FalseClass]
34
- def connected?
35
- !connection.blank?
36
- end
37
-
38
- # Connects with the Sync api
39
- def connect
40
- unless connected?
41
- hostname = 'api.syncano.com'
42
- port = 8200
43
-
44
- sleep(3)
45
-
46
- Thread.new do
47
- begin
48
- EM.run do
49
- EM.connect(hostname, port, Syncano::SyncConnection)
50
- end
51
- rescue Exception => e
52
- p e.message
53
- p e.backtrace
54
- end
55
- end
56
-
57
- timeout = 30
58
-
59
- while connection.blank? && timeout > 0
60
- timeout -= 1
61
- sleep 1
62
- end
63
-
64
- raise ::Syncano::ConnectionError.new('Connection timeout') unless timeout > 0
65
-
66
- timeout = 300
67
-
68
- while (response = connection.get_response('auth')).blank? && timeout > 0
69
- timeout -= 1
70
- sleep 1.0/10.0
71
- end
72
-
73
- raise ::Syncano::ConnectionError.new(response.error) if response.status == 'NOK'
74
- end
75
- end
76
-
77
- # Disconnects with the Sync api
78
- def disconnect
79
- EM.stop if EM::reactor_running?
80
- self.connection = nil
81
- end
82
-
83
- # Reconnects with the Sync api
84
- def reconnect
85
- disconnect
86
- connect
87
- end
88
-
89
- # Gets auth_key based on username and password
90
- # @return [TrueClass, FalseClass]
91
- def login(username, password)
92
- logout
93
- rest_client = ::Syncano.client(api_key: api_key)
94
- self.auth_key = rest_client.users.login(username, password)
95
- !self.auth_key.nil?
96
- end
97
-
98
- # Returns query builder for Syncano::Resources::Subscription objects
99
- # @return [Syncano::QueryBuilder]
100
- def subscriptions
101
- ::Syncano::QueryBuilder.new(self, ::Syncano::Resources::Subscription)
102
- end
103
-
104
- # Returns query builder for Syncano::Resources::Notifications::Base objects
105
- # @return [Syncano::QueryBuilder]
106
- def notifications
107
- ::Syncano::QueryBuilder.new(self, ::Syncano::Resources::Notifications::Base)
108
- end
109
-
110
- # Appends callback for processing notifications to the end of callbacks queue
111
- # @return [Syncano::QueryBuilder]
112
- def append_callback(callback_name, &callback)
113
- connection.append_callback(callback_name, callback)
114
- end
115
-
116
- # Prepends callback for processing notifications to the beginning of callbacks queue
117
- # @return [Syncano::QueryBuilder]
118
- def prepend_callback(callback_name, &callback)
119
- connection.prepend_callback(callback_name, callback)
120
- end
121
-
122
- # Removes callback from the callbacks queue
123
- # @return [Syncano::QueryBuilder]
124
- def remove_callback(callback_name)
125
- connection.remove_callback(callback_name)
126
- end
127
-
128
- # Performs request to Syncano api
129
- # This should be overwritten in inherited classes
130
- # @param [String] resource_name
131
- # @param [String] method_name
132
- # @param [Hash] params additional params sent in the request
133
- # @param [String] response_key for cases when response from api is incompatible with the convention
134
- # @return [Syncano::Response]
135
- def make_request(resource_name, method_name, params = {}, response_key = nil)
136
- raise(::Syncano::ConnectionError.new('Not connected to the Sync Server!')) unless connected?
137
-
138
- response_key ||= resource_name
139
-
140
- packet = ::Syncano::Packets::Call.new(resource_name: resource_name, method_name: method_name, data: params)
141
-
142
- connection.send_data("#{packet.to_json}\n")
143
-
144
- response_packet = nil
145
- timer = 600
146
-
147
- while timer > 0
148
- response_packet = connection.get_response(packet.message_id)
149
- if response_packet.nil?
150
- timer -= 1
151
- sleep 1.0 / 10.0
152
- else
153
- break
154
- end
155
- end
156
-
157
- raise(::Syncano::ApiError.new('Request timeout error!')) if timer == 0
158
-
159
- response = self.class.parse_response(response_key, response_packet.to_response)
160
- response.errors.present? ? raise(::Syncano::ApiError.new(response.errors)) : response
161
- end
162
- end
163
- end
164
- end