Skip to content
This repository was archived by the owner on Oct 19, 2018. It is now read-only.

Commit c7e648c

Browse files
committed
closes #17
1 parent 5e5a662 commit c7e648c

File tree

2 files changed

+94
-30
lines changed

2 files changed

+94
-30
lines changed

lib/hyper-operation/server_op.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,16 @@ def descendants_map_cache
4646
# calling descendants alone may take 10ms in a complex app, so better cache it
4747
@cached_descendants ||= Hyperloop::ServerOp.descendants.map(&:to_s)
4848
end
49-
49+
5050
def run_from_client(security_param, controller, operation, params)
5151
if Rails.env.production?
5252
# in production everything is eager loaded so ServerOp.descendants is filled and can be used to guard the .constantize
5353
Hyperloop::InternalPolicy.raise_operation_access_violation unless Hyperloop::ServerOp.descendants_map_cache.include?(operation)
54-
# however ...
54+
# however ...
5555
else
5656
# ... in development things are autoloaded on demand, thus ServerOp.descendants can be empty or partially filled and above guard
5757
# would fail legal operations. To prevent this, the class has to be loaded first, what .const_get will take care of, and then
58-
# its guarded, to achieve similar behaviour as in production. Doing the const_get first, before the guard,
58+
# its guarded, to achieve similar behaviour as in production. Doing the const_get first, before the guard,
5959
# would not be safe for production and allow for potential remote code execution!
6060
begin
6161
const = Object.const_get(operation)
@@ -70,7 +70,7 @@ def run_from_client(security_param, controller, operation, params)
7070
elsif !_Railway.params_wrapper.method_defined?(security_param)
7171
raise AccessViolation
7272
end
73-
run(params)
73+
run(deserialize_params(params))
7474
.then { |r| return { json: { response: serialize_response(r) } } }
7575
.fail do |e|
7676
::Rails.logger.debug "\033[0;31;1mERROR: Hyperloop::ServerOp failed when running #{operation} with params \"#{params}\": #{e}\033[0;30;21m"

spec/hyper-operation/server_op_spec.rb

Lines changed: 90 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,36 @@
11
require 'spec_helper'
22

33
describe "isomorphic operations", js: true do
4+
5+
before(:each) do
6+
on_client do
7+
class Test < React::Component::Base
8+
def self.receive_count
9+
@@rc ||= 0
10+
@@rc
11+
end
12+
def self.rc_inc
13+
@@rc ||= 0
14+
@@rc += 1
15+
end
16+
before_mount do
17+
Operation.on_dispatch do |params|
18+
self.class.rc_inc
19+
# password is for testing inbound param filtering
20+
state.message! "#{params.message}#{params.try(:password)}"
21+
end
22+
end
23+
render do
24+
if state.message
25+
"The server says '#{state.message}'!"
26+
else
27+
"No messages yet"
28+
end
29+
end
30+
end
31+
end
32+
end
33+
434
context 'uplinking' do
535
before(:each) do
636
stub_const "ServerFacts", Class.new(Hyperloop::ServerOp)
@@ -75,32 +105,6 @@ class ServerFacts < Hyperloop::ServerOp
75105

76106
before(:each) do
77107
stub_const "Operation", Class.new(Hyperloop::ServerOp)
78-
on_client do
79-
class Test < React::Component::Base
80-
def self.receive_count
81-
@@rc ||= 0
82-
@@rc
83-
end
84-
def self.rc_inc
85-
@@rc ||= 0
86-
@@rc += 1
87-
end
88-
before_mount do
89-
Operation.on_dispatch do |params|
90-
self.class.rc_inc
91-
# password is for testing inbound param filtering
92-
state.message! "#{params.message}#{params.try(:password)}"
93-
end
94-
end
95-
render do
96-
if state.message
97-
"The server says '#{state.message}'!"
98-
else
99-
"No messages yet"
100-
end
101-
end
102-
end
103-
end
104108
end
105109

106110
it 'will dispatch to the client' do
@@ -222,4 +226,64 @@ class Operation < Hyperloop::ServerOp
222226
expect_evaluate_ruby('Test.receive_count').to eq(2)
223227
end
224228
end
229+
230+
context "serialization overrides" do
231+
232+
before(:all) do
233+
require 'pusher'
234+
require 'pusher-fake'
235+
Pusher.app_id = "MY_TEST_ID"
236+
Pusher.key = "MY_TEST_KEY"
237+
Pusher.secret = "MY_TEST_SECRET"
238+
require "pusher-fake/support/base"
239+
240+
Hyperloop.configuration do |config|
241+
config.transport = :pusher
242+
config.channel_prefix = "synchromesh"
243+
config.opts = {app_id: Pusher.app_id, key: Pusher.key, secret: Pusher.secret}.merge(PusherFake.configuration.web_options)
244+
end
245+
end
246+
247+
it 'calls the subclasses serializer and deserializer methods' do
248+
isomorphic do
249+
class Operation < Hyperloop::ServerOp
250+
param :acting_user, nils: true
251+
param :counter
252+
outbound :message
253+
step {params.message = 'hello'}
254+
step {params.counter + 1}
255+
def self.serialize_params(hash)
256+
hash['counter'] += 1
257+
hash
258+
end
259+
def self.deserialize_params(hash)
260+
hash['counter'] += 1
261+
hash
262+
end
263+
def self.serialize_response(response)
264+
response + 1
265+
end
266+
def self.deserialize_response(response)
267+
response + 1
268+
end
269+
def self.serialize_dispatch(hash)
270+
hash[:message] += ' serialized'
271+
hash
272+
end
273+
def self.deserialize_dispatch(hash)
274+
hash[:message] += ' deserialized'
275+
hash
276+
end
277+
end
278+
end
279+
stub_const "OperationPolicy", Class.new
280+
OperationPolicy.always_allow_connection
281+
mount 'Test'
282+
283+
expect_promise do
284+
Operation.run(counter: 1)
285+
end.to eq(6)
286+
expect(page).to have_content("The server says 'hello serialized deserialized'!")
287+
end
288+
end
225289
end

0 commit comments

Comments
 (0)