clientside 0.2.1 → 0.3

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.
@@ -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: