plezi 0.12.22 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/LICENSE.txt +17 -18
  4. data/README.md +54 -698
  5. data/Rakefile +7 -4
  6. data/bin/config.ru +22 -0
  7. data/{test → bin}/console +4 -6
  8. data/bin/hello_world +52 -0
  9. data/bin/setup +8 -0
  10. data/exe/plezi +145 -0
  11. data/lib/plezi.rb +24 -137
  12. data/lib/plezi/activation.rb +28 -0
  13. data/lib/plezi/api.rb +62 -0
  14. data/lib/plezi/controller/controller.rb +259 -0
  15. data/lib/plezi/controller/controller_class.rb +176 -0
  16. data/lib/plezi/controller/cookies.rb +40 -0
  17. data/lib/plezi/helpers.rb +60 -0
  18. data/lib/plezi/rake.rb +2 -24
  19. data/lib/plezi/render/erb.rb +34 -0
  20. data/lib/plezi/render/has_cache.rb +36 -0
  21. data/lib/plezi/render/markdown.rb +63 -0
  22. data/lib/plezi/render/render.rb +49 -0
  23. data/lib/plezi/render/sass.rb +55 -0
  24. data/lib/plezi/render/slim.rb +33 -0
  25. data/lib/plezi/router/adclient.rb +23 -0
  26. data/lib/plezi/router/assets.rb +67 -0
  27. data/lib/plezi/router/errors.rb +29 -0
  28. data/lib/plezi/router/route.rb +112 -0
  29. data/lib/plezi/router/router.rb +120 -0
  30. data/lib/plezi/version.rb +1 -1
  31. data/lib/plezi/websockets/message_dispatch.rb +91 -0
  32. data/lib/plezi/websockets/redis.rb +55 -0
  33. data/plezi.gemspec +25 -16
  34. data/resources/404.erb +5 -4
  35. data/resources/500.erb +5 -4
  36. data/resources/{500.html → 503.html} +8 -9
  37. data/resources/client.js +253 -0
  38. data/resources/config.ru +5 -36
  39. data/resources/ctrlr.rb +34 -0
  40. data/resources/gemfile +4 -0
  41. data/resources/mini_app.rb +28 -82
  42. data/resources/mini_exec +7 -0
  43. data/resources/mini_welcome_page.html +0 -0
  44. data/resources/procfile +3 -0
  45. data/resources/rakefile +4 -8
  46. data/resources/routes.rb +9 -26
  47. data/resources/{websockets.js → simple-client.js} +3 -3
  48. metadata +60 -85
  49. data/bin/plezi +0 -104
  50. data/docs/async_helpers.md +0 -245
  51. data/docs/controllers.md +0 -27
  52. data/docs/logging.md +0 -49
  53. data/docs/routes.md +0 -209
  54. data/docs/websockets.md +0 -213
  55. data/lib/plezi/builders/ac_model.rb +0 -59
  56. data/lib/plezi/builders/app_builder.rb +0 -137
  57. data/lib/plezi/builders/builder.rb +0 -43
  58. data/lib/plezi/builders/form_builder.rb +0 -27
  59. data/lib/plezi/common/api.rb +0 -92
  60. data/lib/plezi/common/cache.rb +0 -122
  61. data/lib/plezi/common/defer.rb +0 -21
  62. data/lib/plezi/common/dsl.rb +0 -94
  63. data/lib/plezi/common/redis.rb +0 -65
  64. data/lib/plezi/common/renderer.rb +0 -141
  65. data/lib/plezi/common/settings.rb +0 -52
  66. data/lib/plezi/handlers/controller_core.rb +0 -106
  67. data/lib/plezi/handlers/controller_magic.rb +0 -284
  68. data/lib/plezi/handlers/http_router.rb +0 -205
  69. data/lib/plezi/handlers/placebo.rb +0 -112
  70. data/lib/plezi/handlers/route.rb +0 -216
  71. data/lib/plezi/handlers/session.rb +0 -109
  72. data/lib/plezi/handlers/stubs.rb +0 -156
  73. data/lib/plezi/handlers/ws_identity.rb +0 -253
  74. data/lib/plezi/handlers/ws_object.rb +0 -308
  75. data/lib/plezi/helpers/http_sender.rb +0 -84
  76. data/lib/plezi/helpers/magic_helpers.rb +0 -104
  77. data/lib/plezi/helpers/mime_types.rb +0 -1995
  78. data/lib/plezi/oauth.rb +0 -5
  79. data/lib/plezi/oauth/auth_controller.rb +0 -229
  80. data/logo/dark.png +0 -0
  81. data/logo/light.png +0 -0
  82. data/logo/sign.png +0 -0
  83. data/resources/404.haml +0 -121
  84. data/resources/404.html +0 -124
  85. data/resources/404.slim +0 -120
  86. data/resources/500.haml +0 -120
  87. data/resources/500.slim +0 -120
  88. data/resources/Gemfile +0 -86
  89. data/resources/code.rb +0 -8
  90. data/resources/controller.rb +0 -142
  91. data/resources/database.yml +0 -33
  92. data/resources/db_ac_config.rb +0 -59
  93. data/resources/db_dm_config.rb +0 -51
  94. data/resources/db_sequel_config.rb +0 -33
  95. data/resources/en.yml +0 -204
  96. data/resources/haml_config.rb +0 -6
  97. data/resources/i18n_config.rb +0 -14
  98. data/resources/initialize.rb +0 -49
  99. data/resources/mini_exec.rb +0 -7
  100. data/resources/oauth_config.rb +0 -24
  101. data/resources/plezi_client.js +0 -198
  102. data/resources/plezi_websockets.html +0 -47
  103. data/resources/redis_config.rb +0 -42
  104. data/resources/slim_config.rb +0 -11
  105. data/resources/welcome_page.html +0 -272
  106. data/test/dispatch +0 -58
  107. data/test/hello_world +0 -13
  108. data/test/plezi_tests.rb +0 -581
data/docs/controllers.md DELETED
@@ -1,27 +0,0 @@
1
- # Plezi Controllers - Virtual folders, RESTful requests, Websockets and more.
2
-
3
- In the core of Plezi's framework is a smart Object Oriented Router which acts like a "virtual folder" with RESTful routing and Websocket support.
4
-
5
- RESTful routing and Websocket callback support both allow us to use conventionally named methods in our Controller to achive common tasks. Such names methods, as will be explored further on, include the `update`, `save` and `show` RESTful method names, as well as the `on_open`, `on_message(data)` and `on_close` Websocket callbacks.
6
-
7
- The first layer of this powerful routing system is [the Plezi's Http Router and the core method `Plezi.route` which we already explored](./routes.md).
8
-
9
- The second layer of this powerful routing system is the Controller class which we are about explore.
10
-
11
- ## What is a Controller Class?
12
-
13
- (todo: write documentation)
14
-
15
- ### A Virtual Folder
16
-
17
- (todo: write documentation)
18
-
19
- ### RESTful methods
20
-
21
- (todo: write documentation)
22
-
23
- ### Websocket Callbacks
24
-
25
- (todo: write documentation)
26
-
27
-
data/docs/logging.md DELETED
@@ -1,49 +0,0 @@
1
- # Plezi's Logging
2
-
3
- (todo: write documentation)
4
-
5
- Inside Plezi's core code is a pure Ruby IO reactor called [Iodine](https://github.com/boazsegev/iodine), a wonderful Asynchronous Workflow Engine that allows us to enjoy both Multi-Threading and Multi-Processing.
6
-
7
- Plezi leverages [Iodine's](https://github.com/boazsegev/iodine) logging support to help you log to both files and STDOUT (terminal screen) - either one or both
8
-
9
- You can read more about [Iodine](https://github.com/boazsegev/iodine) and it's amazing features in it's [documentation](http://www.rubydoc.info/github/boazsegev/iodine/master).
10
-
11
- ## Setting up a Logger
12
-
13
- Logging is based on the standard Ruby `Logger`, and replaceing the default logger (STDOUT) to a different logger (such as a file based logger), is as simple as:
14
-
15
- ```ruby
16
- Iodine.logger = Logger.new filename
17
- # # the same can be done using Plezi.logger, which automatically defers to Iodine.logger
18
- # Plezi.logger = Logger.new filename
19
- ```
20
-
21
-
22
- ## Logging Helpers Methods
23
-
24
- // to do: complete docs
25
-
26
- ### `Iodine.info`
27
-
28
- // to do: complete docs
29
-
30
- ### `Iodine.debug`
31
-
32
- // to do: complete docs
33
-
34
- ### `Iodine.warn`
35
-
36
- // to do: complete docs
37
-
38
- ### `Iodine.error`
39
-
40
- // to do: complete docs
41
-
42
- ### `Iodine.fatal`
43
-
44
- // to do: complete docs
45
-
46
- ### `Iodine.log(raw_string)`
47
-
48
- // to do: complete docs
49
-
data/docs/routes.md DELETED
@@ -1,209 +0,0 @@
1
- # Plezi's Smart Routing System
2
-
3
- In the core of Plezi's framework is a smart Object Oriented Router which acts like a "virtual folder" with RESTful routing and Websocket support.
4
-
5
- RESTful routing and Websocket callback support both allow us to use conventionally named methods in our Controller to achive common tasks. Such names methods, as will be explored further on, include the `update`, `save` and `show` RESTful method names, as well as the `on_open`, `on_message(data)` and `on_close` Websocket callbacks.
6
-
7
- The first layer of this powerful routing system is the Plezi's Http Router and the core method `Plezi.route`.
8
-
9
- ## What is a Route?
10
-
11
- Routes are what connects different URLs to different parts of our code.
12
-
13
- We when we visit `www.example.com/users/index` we expect a different page than when we go to `www.example.com/users/1`. This is because we expect the first URL to provide a page with the list of users while we expect the second URL to show us a specific user's page or data.
14
-
15
- in the example above, all the requests are made to the server at `www.example.com` and it is the server's inner workings - the server's inner router - that directs the `/users/index` to one part of our code and `/users/1` to another.
16
-
17
- Like all web applications, Plezi also has an inner router which routes each request to the corresponding method or code.
18
-
19
- Plezi's routing system was designed to build upon conventions used in other routing systems together with an intuitive approach that allows for agail application development.
20
-
21
- \* It should be noted that except for file handling and the asset pipeline - which are file-system dependent - routes are case-sensitive.
22
-
23
- ## Defining a Route
24
-
25
- We define a route using Plezi's `Plezi.route` method or the shortcut DSL method `route` (without the `Plezi.` part).
26
-
27
- This method accept a String, or Regexp, that should point to a "group" of routes.
28
-
29
- The method also requires either a class that "controls" that group of routes or a block of code that responds to that route.
30
-
31
- Here are a few examples for valid routes. You can run the following script in the `irb` terminal:
32
-
33
- ```ruby
34
- require 'plezi'
35
-
36
- class UsersController
37
- def index
38
- "All Users"
39
- end
40
- end
41
-
42
- # the "/users" group can be extended. for now, it will only answer: "/users" or "/users/index"
43
- # this is because that's all that UsersController defines.
44
- Plezi.route "/users", UsersController
45
-
46
- # this route isn't grouped under a controller.
47
- # it will answer to "/people" and "/people/something" with the same response.
48
- Plezi.route("/people") { "People" }
49
-
50
- # this route includes a catch-all at the end and will
51
- # catch anything that starts with "/stuff/"
52
- Plezi.route("/stuff/*") { "More and more stuff" }
53
-
54
- # this is catch-all that answers any requests not yet answered.
55
- Plezi.route("*") { "Lost?" }
56
-
57
- # this route will never be seen,
58
- # because the catch-all route answers any request before it gets here.
59
- Plezi.route("/never-seen") { "You can't see me..." }
60
-
61
-
62
- exit
63
- ```
64
-
65
- As you may have noticed, the route's order of creation was important and established an order of precedence.
66
-
67
- If the order of precedence were not to exist, we couldn't create a catch-all route, in fear that it might respond to valid requests.
68
-
69
- ### The `:id` parameter
70
-
71
- In order to manage route "groups", Plezi's router attmpt to add an optional `:id` parameter at the end of the route. This is only possible when the route doesn't end with a catch-all (if a catch-all exists, the `:id` parameter can't be isolated).
72
-
73
- So, the following two routes are identical:
74
-
75
- ```ruby
76
- require 'plezi'
77
-
78
- class UsersController
79
- def index
80
- "All Users"
81
- end
82
- end
83
-
84
- Plezi.route "/users", UsersController
85
-
86
- route "/users/(:id)", UsersController
87
-
88
- exit
89
- ```
90
-
91
- It's possible to add different optional parameters either before or after the (:id) parameter... but the (:id) parameter is special and it WILL effect the way the Controller reacts to the request - this is what allows the controller to react to RESTful requests (more information about this later on).
92
-
93
- For example:
94
-
95
- ```ruby
96
- require 'plezi'
97
-
98
- class UsersController
99
- def index
100
- "All Users"
101
- end
102
- def show
103
- params[:name] ||= "unknown"
104
- "Your name is #{ params[:name] }... why are you looking for user id '#{ params[:id] }'?"
105
- end
106
- end
107
-
108
- route "/users/(:id)/(:name)", UsersController
109
-
110
- exit
111
- ```
112
-
113
- * now visit [/users/1/John](http://localhost:3000/users/1/John)
114
-
115
- As you noticed, providing an `:id` parameter invoked the RESTful method `show`. This is only one possible outcome. We will discuss this more [when we look at the Controller](./controllers.md) being used as a virtual folder and as we discuss about RESTful method.
116
-
117
- ### More inline parameters
118
-
119
- Inline parameters come in more flavors:
120
-
121
- * Required parameters signified only by the `:` sign. i.e. `'/users/:name'`.
122
- * Optional parameters, as seen before. i.e. `'/users/(:name)'`.
123
- * Required parameters matching a specific pattern, signified by the `:` sign with a `{pattern}`. i.e. `'/users/:date{[\d]{8}}'` (requiring 8 digit date, such as `'20151231'`).
124
- * Optional parameters matching a specific pattern. i.e. `'/users/(:date){[\d]{8}}'` (optional 8 digit date, such as `'20151231'`).
125
-
126
- Using inline parameters, it's possible to achive great flexability with the same route, allowing our code to be better organized. This is especially helpful when expecting data to be received using AJAX or when creating an accessible API for native apps to utilize.
127
-
128
- It should be noted, when using parameters matching a specific pattern, that since a parameter matches against the whole of the pattern, parenthesis within the shouldn't be used and could lead to parsing errors.
129
-
130
- ### Re-Write Routes
131
-
132
- Sometimes, we want some of our routes to share common optional (or required) parameters. This is where "Re-Write" routes come into play.
133
-
134
- A common use-case, is for setting the locale or language for the response.
135
-
136
- To create a re-write route, we set the "controller" to false.
137
-
138
- For Example:
139
-
140
-
141
- ```ruby
142
- require 'plezi'
143
-
144
- class UsersController
145
- def index
146
- case params[:locale]
147
- when 'sp'
148
- "Hola!"
149
- when 'fr'
150
- "Bonjour!"
151
- when 'ru'
152
- "Здравствуйте!"
153
- when 'jp'
154
- "こんにちは!"
155
- else
156
- "Hello!"
157
- end
158
- end
159
- end
160
-
161
- # this is the re-write route:
162
- Plezi.route "/(:locale){en|sp|fr|ru|jp}/*", false
163
-
164
- # this route inherits the `:locale`'s result
165
- # try:
166
- # /fr/users
167
- # /ru/users
168
- # /en/users
169
- # /it/users # => isn't a valid locale
170
- Plezi.route "/users", UsersController
171
-
172
- exit
173
- ```
174
-
175
- Try the code above and visit:
176
-
177
- * [localhost:3000/fr/users](http://localhost:3000/fr/users)
178
- * [localhost:3000/ru/users](http://localhost:3000/ru/users)
179
- * [localhost:3000/en/users](http://localhost:3000/en/users)
180
- * [localhost:3000/it/users](http://localhost:3000/it/users)
181
-
182
- Notice the re-write route contained a catch all. This catch-all is automatically added if missing. The catch-all is the part of the path that will remain for the following routes to check against.
183
-
184
- ### Routes with Blocks instead of Controllers
185
-
186
- Routes that respond with a block of code can receive the `request` and `response` objects, to be used within the block of code (the controller also has access to these objects).
187
-
188
- These Routes favor a global response over the different features offered by Controllers (i.e. RESTful routing and virtual folder method routing). Also, the block of code does NOT inherit all the magical abilities bestowed on Controllers which could allow for a slight increase in response time.
189
-
190
- Here's a more powerful example of a route with a block of code, this time using the `request` and `response` passed on to it:
191
-
192
- ```ruby
193
- require 'plezi'
194
-
195
- Plezi.route "/(:id)/(:value)" do |request, response|
196
- if request.params[:id]
197
- response.cookies[request.params[:id]] = request.params[:value]
198
- response << "Set the #{request.params[:id]} cookie to #{request.params[:value] || 'be removed'}.\n\n"
199
- end
200
- response << "Your cookies are:\n"
201
- request.cookies.each {|k, v| response << "* #{k}: #{v}\n" }
202
- end
203
-
204
- exit
205
- ```
206
-
207
- ## The next step
208
-
209
- Now that we have learned more about the power of Plezi's routing system, it's time to [learn more about what Controller classes can do for us](./controllers.md).
data/docs/websockets.md DELETED
@@ -1,213 +0,0 @@
1
- # Plezi Websockets
2
-
3
- Inside Plezi's core code is the pure Ruby HTTP and Websocket Server (and client) that comes with [Iodine](https://github.com/boazsegev/iodine), a wonderful little server that supports an effective websocket functionality both as a server and as a client.
4
-
5
- Plezi augmentes Iodine by adding auto-Redis support for scaling and automatically mapping each Contoller Class as a broadcast channel and each server instance to it's own unique channel - allowing unicasting to direct it's message at the target connection's server and optimizing resources.
6
-
7
- Reading through this document, you should remember that Plezi's websocket connections are object oriented - they are instances of Controller classes that answer a specific url/path in the Plezi application. More than one type of connection (Controller instance) could exist in the same application.
8
-
9
- ## A short intro to Websockets (skip this if you can)
10
-
11
- In a very broad sense, Websockets allow the browser communicate with the server in a bi-directional manner. This overcomes some of the limitations imposed by Http alone, allowing (for instance) to push real-time data, such as chat messages or stock quotes, directly to the browser.
12
-
13
- In essense, while Http's worflow is a call and response (the browser "calls", the server "responds"), Websockets is a conversation, sometimes with long pauses, where both sides can speak whenever they feel the need to.
14
-
15
- This, in nature, requires that both sides of the conversation establish a common language... this part is pretty much up to each application.
16
-
17
- It's easy to think about it this way:
18
-
19
- the browsers starts a call-response sequence. All websocket connections start as Http call-response. The browser shouts over the internet "I want to start a conversation".
20
-
21
- The server responds: "Sure thing, let's talk".
22
-
23
- Than they start their websocket conversation, keeping the connection between them open. The server can also answer "no thanks", but than there's no websocket connection and the Http connection will probably die out (unless it's Http/2).
24
-
25
- ### initiating a websocket connection
26
-
27
- The websocket connection is initiated by the browser using `Javascript`.
28
-
29
- The `Javascript` should, in most applications, handle the following three Websocket `Javascript` events:
30
-
31
- - `onopen`: a connection was established.
32
- - `onmessage`: a message was received through the connection.
33
- - `onclose`: an open connection had closed, or a connection initiated couldn't be established.
34
-
35
- Here is a common enough example of a script designed to open a websocket:
36
-
37
- ```js
38
-
39
- websocket = NaN
40
-
41
- function init_websocket()
42
- {
43
- // no need to renew socket connection if it's open
44
- if(websocket && websocket.readyState == 1) return true;
45
-
46
- // initiate the url for the websocket... this is a bit of an overkill,
47
- // but it will allow you to copy & paste decent code
48
- var ws_uri = (window.location.protocol.match(/https/) ? 'wss' : 'ws') + '://' + window.document.location.host
49
-
50
- // initiate a new websocket connection
51
- websocket = new WebSocket(ws_uri);
52
-
53
- // define the onopen event callback
54
- websocket.onopen = function(e) {
55
- // what do you want to do now?
56
- // maybe send a message?
57
- websocket.send("Hello there!");
58
- // a common practice is to use JSON
59
- var msg = JSON.stringify({msg: 'chat', data: 'Hello there!'})
60
- websocket.send(msg);
61
- };
62
-
63
- // define the onclose event callback
64
- websocket.onclose = function(e) {
65
- // you probably want to reopen the websocket if it closes
66
- setTimeout( init_websocket, 100 );
67
- };
68
-
69
- // define the onmessage event callback
70
- websocket.onmessage = function(e) {
71
- // what do you want to do now?
72
- console.log(e.data);
73
- // to use JSON, use:
74
- // msg = JSON.parse(e.data);
75
- };
76
- }
77
-
78
- init_websocket();
79
-
80
- ```
81
-
82
- As you can tell from reading through the code, this means that the browser will open a new connection to the server, using the websocket protocol.
83
-
84
- In our example the script sent a message: `"Hello there!"`. It's up to your code to decide what to do with the data it receives, be it using JSON or raw data.
85
-
86
- When data comes in from the browser, the `onmessage` event is raised. It's up to your script to decypher the meaning of that message within the `onmessage` callback.
87
-
88
- ###
89
-
90
- No we know a bit about what Websockets are and how to initiate a websocket connection to send and receive data... next up, how to get Plezi to answer (or refuse) websocket requests?
91
-
92
- ## Communicating between the application and clients
93
-
94
- (todo: write documentation)
95
-
96
-
97
- ## Communicating between different Websocket clients
98
-
99
- Plezi supports three models of communication:
100
-
101
- ### General websocket communication
102
-
103
- When using this type of communication, it is expected that each connection's controller provide a protected instance method with a name matching the event name and that this method will accept, as arguments, the data sent with the event.
104
-
105
- This type of communication includes:
106
-
107
- - **Multicasting**:
108
-
109
- Use `multicast` to send an event to all the websocket connections currently connected to the application (including connections on other servers running the application, if Redis is used).
110
-
111
- - **Unicasting**:
112
-
113
- Use `unicast` to send an event to a specific websocket connection.
114
-
115
- This uses a unique UUID that contains both the target server's information and the unique connection identifier. This allows a message to be sent to any connected websocket across multiple application instances when using Redis, minimizing network activity and server load as much as effectively possible.
116
-
117
- Again, exacly like when using multicasting, any connection targeted by the message is expected to implemnt a method matching the name of the event, which will accept (as arguments) the data sent.
118
-
119
- For instance, when using:
120
-
121
- unicast target_id, :event_name, "string", and: :hash
122
-
123
- The receiving websocket controller is expected to have a protected method named `event_name` like so:
124
-
125
- ```ruby
126
- class MyController
127
- #...
128
- protected
129
- def event_name str, options_hash
130
- #...
131
- end
132
- end
133
- ```
134
-
135
- ### Object Oriented communication
136
-
137
- Use `broadcast` or `Controller.broadcast` to send an event to a all the websocket connections that are managed by a specific Controller class.
138
-
139
- The controller is expected to provide a protected instance method with a name matching the event name and that this method will accept, as arguments, the data sent with the event.
140
-
141
- The benifit of using this approach is knowing exacly what type of objects handle the message - all the websocket connections receiving the message will be members (instances) of the same class.
142
-
143
- For instance, when using:
144
-
145
- MyController.broadcast :event_name, "string", and: :hash
146
-
147
- The receiving websocket controller is expected to have a protected method named `event_name` like so:
148
-
149
- ```ruby
150
- class MyController
151
- #...
152
- protected
153
- def event_name str, options_hash
154
- #...
155
- end
156
- end
157
- ```
158
-
159
- ### Identity oriented communication
160
-
161
- Identity oriented communication will only work if Plezi's Redis features are enabled. To enable Plezi's automatic Redis features (such as websocket scaling automation, Redis Session Store, etc'), use:
162
-
163
- ENV['PL_REDIS_URL'] ||= "redis://user:password@redis.example.com:9999"
164
-
165
- Use `#register_as` or `#notify(identity, event_name, data)` to send make sure a certain Identity object (i.e. an app's User) receives notifications either in real-time (if connected) or the next time the identity connects to a websocket and identifies itself using `#register_as`.
166
-
167
- Much like General Websocket Communication, the identity can call `#register_as` from different Controller classes and it is expected that each of these Controller classes implement the necessary methods.
168
-
169
- It is a good enough practice that an Identity based websocket connection will utilize the `#on_open` callback to authenticate and register an identity. For example:
170
-
171
- ```ruby
172
- class MyController
173
- #...
174
- def on_open
175
- user = suthenticate_user
176
- close unless user
177
- register_as user.id
178
- end
179
-
180
- protected
181
-
182
- def event_name str, options_hash
183
- #...
184
- end
185
- end
186
- ```
187
-
188
- It is recommended that the authentication and registration are split into two different events - the `pre_connect` for authentication and the `on_open` for registration - since, as a matter of security, it is better to prevent someone from entering (not establishing a websocket connection) than throwing them out (closing the connection within the `on_open` event).
189
-
190
- Sending messages to the identity is similar to the other communication API methods. For example:
191
-
192
- notify user_id, :event_name, "string data", hash: :data, more_hash: :data
193
-
194
- As expected, it could be that an Identity will never revisit the application or messages become outdated after a while. For this reason limits must be set as to how long any specific "mailbox" should remain alive in the database when it isn't acessed by the Identity. This is done within the `register_as` method i.e.:
195
-
196
- register_as user.id, lifetime: 1_814_400 # 21 days
197
-
198
- Another consideration is that more than one "lifetime" setting might be required for defferent types of messages. The solution for this will be to allow a single connection to register as a number of different identities, each with it's own lifetime:
199
-
200
- # to register:
201
- register_as "#{user.id}-long", lifetime: 1_814_400 # 21 days
202
- register_as "#{user.id}-short", lifetime: 3_600 # 1 hour
203
-
204
- # to notify:
205
- notify "#{user.id}-long", :event_name #...
206
- notify "#{user.id}-short", :event_name #...
207
-
208
- It should be noted that the lifetime is for the identity's lifetime and NOT the notification's lifetime. A notification sent a second before the identity "dies" will live for only a second and notify will return `true` all the same.
209
-
210
- `notify` should return `true` or `false`, depending on whether the identity still exists.
211
-
212
- (todo: write documentation)
213
-