clientside 0.2.1 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,7 +4,7 @@ var makeClientsideProxy = (function() {
4
4
  };
5
5
 
6
6
  var remoteInvoke = function(socket, obj, method, args) {
7
- var request = {"receiver": obj, "method": method, "arguments": args};
7
+ var request = {"receiver": obj, "method_": method, "arguments": args};
8
8
  var id = request.id = Date.now();
9
9
  var promise = new Promise(function(resolve, reject) {
10
10
  socket.pending[id] = [resolve, reject];
@@ -42,7 +42,7 @@ var makeClientsideSocket = (function() {
42
42
  }
43
43
  }
44
44
  }
45
- else if (obj instanceof Object) {
45
+ else if (obj instanceof Object) {
46
46
  for (key in obj) {
47
47
  if (obj[key].__clientside__) {
48
48
  obj[key] = makeClientsideProxy(socket, obj[key]);
@@ -58,6 +58,7 @@ var makeClientsideSocket = (function() {
58
58
  socket.onmessage = function(event) {
59
59
  var response = JSON.parse(event.data);
60
60
  var callbacks = socket.pending[response.id];
61
+ delete socket.pending[response.id];
61
62
  if (!callbacks) {
62
63
  return;
63
64
  }
@@ -66,7 +67,7 @@ var makeClientsideSocket = (function() {
66
67
  callbacks[0](response.result); // resolve
67
68
  }
68
69
  else {
69
- callbacks[1](); // reject
70
+ callbacks[1](response.message); // reject
70
71
  }
71
72
  };
72
73
  return socket;
@@ -75,3 +76,5 @@ var makeClientsideSocket = (function() {
75
76
  return socketMaker;
76
77
  })();
77
78
 
79
+ // vim:tabstop=4 shiftwidth=4 expandtab:
80
+
data/lib/clientside.rb CHANGED
@@ -2,8 +2,9 @@ require 'json'
2
2
  require 'faye/websocket'
3
3
  require 'rack/static'
4
4
  require 'securerandom'
5
+ require 'ostruct'
5
6
 
6
- class Clientside
7
+ module Clientside
7
8
  module Accessible
8
9
  class << self
9
10
  attr_accessor :cur_os
@@ -37,7 +38,8 @@ class Clientside
37
38
  def to_json(*args)
38
39
  name = self.class.name
39
40
  methods = self.class.js_allowed
40
- h = {__clientside__: true, __clientside_id__: object_id, methods: methods}
41
+ h = {__clientside__: true, __clientside_id__: object_id,
42
+ methods: methods}
41
43
  h.to_json *args
42
44
  end
43
45
  end
@@ -45,8 +47,10 @@ class Clientside
45
47
  class NoResMiddleware
46
48
  RPATH = '/__clientside_sock__/'
47
49
  MAX_OBJECTS = 256
50
+ PENDING_TTL = 5 * 60
48
51
 
49
52
  @@pending_sockets = {}
53
+ @@pending_expiries = []
50
54
  @@sockets = {}
51
55
 
52
56
  def initialize(app)
@@ -58,11 +62,18 @@ class Clientside
58
62
  end
59
63
 
60
64
  def handle_message(cmd, ws)
61
- raise unless cmd[:receiver].kind_of? Clientside::Accessible
62
- allowed = cmd[:receiver].class.js_allowed
63
- raise unless allowed.include? cmd[:method].to_sym
64
-
65
- result = cmd[:receiver].send cmd[:method], *cmd[:arguments]
65
+ can_receive = cmd.receiver.kind_of? Accessible
66
+ raise "receiver is not js-accessible" unless can_receive
67
+ is_name = cmd.method_.respond_to? :to_sym
68
+ raise "not a method name: #{cmd.method_}" unless is_name
69
+ allowed = cmd.receiver.class.js_allowed.include? cmd.method_.to_sym
70
+ raise "unknown method: #{cmd.method_}" unless allowed
71
+
72
+ begin
73
+ result = cmd.receiver.send cmd.method_, *cmd.arguments
74
+ rescue ArgumentError => e
75
+ raise e.message
76
+ end
66
77
  o_tj_source = JSON::Ext::Generator::GeneratorMethods::Object
67
78
  result = nil if result.method(:to_json).owner.equal? o_tj_source
68
79
 
@@ -70,14 +81,16 @@ class Clientside
70
81
  unless @@sockets[ws].length >= MAX_OBJECTS
71
82
  register_obj ws, result
72
83
  else
73
- raise
84
+ raise "too many objects allocated"
74
85
  end
75
86
  end
76
- ws.send JSON.dump({status: 'success', id: cmd[:id], result: result})
87
+ ws.send JSON.dump({status: 'success', id: cmd.id, result: result})
77
88
  end
78
89
 
79
90
  def call(env)
80
- if Faye::WebSocket.websocket? env and env['REQUEST_PATH'].start_with? RPATH
91
+ is_websocket = Faye::WebSocket.websocket? env
92
+ for_us = env['REQUEST_PATH'].start_with? RPATH
93
+ if is_websocket and for_us
81
94
  env['REQUEST_PATH'] =~ %r(\A#{RPATH}(.+)\Z)
82
95
  cid = $1
83
96
  objs = @@pending_sockets.delete(cid)
@@ -92,10 +105,27 @@ class Clientside
92
105
  ws.on :message do |event|
93
106
  begin
94
107
  cmd = JSON.parse event.data, symbolize_names: true
95
- cmd = Clientside::Accessible.reinflate cmd, @@sockets[ws]
108
+ needed = [:receiver, :method_, :arguments, :id]
109
+ unless needed.all? {|k| cmd.key? k}
110
+ if cmd.key? :id
111
+ ws.send JSON.dump({status: 'error',
112
+ message: 'invalid request', id: cmd[:id]})
113
+ end
114
+ next
115
+ end
116
+ cmd = Accessible.reinflate cmd, @@sockets[ws]
117
+ cmd = OpenStruct.new cmd
96
118
  handle_message cmd, ws
97
- rescue RuntimeError, KeyError => e
98
- ws.send JSON.dump({status: 'error', id: cmd[:id]})
119
+ rescue JSON::ParserError
120
+ rescue KeyError => e
121
+ e.message =~ /\Akey not found: (.+)\Z/
122
+ missing_id = $1
123
+ message = "unknown object id: #{missing_id}"
124
+ ws.send JSON.dump({status: 'error',
125
+ message: message, id: cmd.id})
126
+ rescue RuntimeError => e
127
+ ws.send JSON.dump({status: 'error',
128
+ message: e.message, id: cmd.id})
99
129
  end
100
130
  end
101
131
 
@@ -114,6 +144,11 @@ class Clientside
114
144
  objs = Hash[objs.map {|o| [o.object_id, o]}]
115
145
  cid = SecureRandom.hex
116
146
  @@pending_sockets[cid] = objs
147
+ @@pending_expiries << [cid, Time.now + PENDING_TTL]
148
+ until @@pending_expiries.first[1] > Time.now
149
+ ecid, _ = @@pending_expiries.shift
150
+ @@pending_sockets.delete ecid
151
+ end
117
152
  cid
118
153
  end
119
154
  end
@@ -128,9 +163,9 @@ class Clientside
128
163
 
129
164
  def self.embed(objs)
130
165
  objs.each do |var, obj|
131
- raise ArgumentError, "invalid js var name" unless var =~ /\A[a-zA-Z_]\w*\Z/
166
+ raise ArgumentError, "invalid var name" unless var =~ /\A[a-zA-Z_]\w*\Z/
132
167
  end
133
- cid = Clientside::Middleware.add_pending objs.values
168
+ cid = Middleware.add_pending objs.values
134
169
  sock_var = '$__clientside_socket__'
135
170
  js = ""
136
171
  js << %Q(<script src="/__clientside_res__/promise.min.js"></script>\n)
@@ -150,5 +185,5 @@ class Clientside
150
185
  end
151
186
  end
152
187
 
153
- # vim:tabstop=2 shiftwidth=2 noexpandtab:
188
+ # vim:tabstop=2 shiftwidth=2 expandtab:
154
189
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clientside
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: '0.3'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: