whoisonline 0.1.0 → 0.1.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.
- checksums.yaml +4 -4
- data/README.md +38 -4
- data/lib/whoisonline/configuration.rb +2 -1
- data/lib/whoisonline/engine.rb +14 -0
- data/lib/whoisonline/presence_controller.rb +37 -0
- data/lib/whoisonline/redis_store.rb +7 -0
- data/lib/whoisonline/tracker.rb +9 -0
- data/lib/whoisonline/version.rb +1 -1
- data/lib/whoisonline.rb +1 -1
- metadata +11 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8d9ca4af0f12891b59ecbceb8666fbbb49d05043bc29bce86caeb85f1fa5d92d
|
|
4
|
+
data.tar.gz: d87b7d98171a1b83793d6291c5ccaaf452a372d18554b532435522938486b5b2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 889ddb36bc48126bac9d70df40140381cef90c66a083bc89c533e60b29d44bc117ff9bb1f4637a2f0b60fb6dd04b399fce74db9b232b32362e4a23bf88a0ff98
|
|
7
|
+
data.tar.gz: 102ad2155cee722972f09558454f57abc61a652453ac70a05ace23833948ced1f0191b999eb313199a6f2c17be097fd53e7b2339d74e68364199dbffcc0e259e
|
data/README.md
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
# WhoIsOnline
|
|
2
2
|
|
|
3
|
-
Track
|
|
3
|
+
Track "who is online right now?" in Rails 7+ using Redis TTL. No database writes, production-safe, and auto-hooks into controllers via a Rails Engine.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
- Rails Engine auto-includes a controller concern to mark users online.
|
|
7
7
|
- Works with `current_user` from any auth system (Devise, custom, etc.).
|
|
8
8
|
- TTL-based presence in Redis, no tables required.
|
|
9
|
+
- **Automatic offline detection** when users close their browser/tab.
|
|
10
|
+
- **Visible-only heartbeats**: only ping while the tab is visible/active (configurable interval).
|
|
9
11
|
- Throttled Redis writes to reduce load (configurable).
|
|
10
12
|
- Safe SCAN-based counting; no `KEYS`.
|
|
11
|
-
- Configurable Redis client, TTL, throttle duration, user id method, controller accessor, and
|
|
13
|
+
- Configurable Redis client, TTL, throttle duration, user id method, controller accessor, namespace, and heartbeat interval.
|
|
12
14
|
|
|
13
15
|
## Installation
|
|
14
16
|
Add to your Gemfile:
|
|
15
17
|
|
|
16
18
|
```ruby
|
|
17
|
-
gem "whoisonline", github: "
|
|
19
|
+
gem "whoisonline", github: "KapilDevPal/WhoIsOnline"
|
|
18
20
|
```
|
|
19
21
|
|
|
20
22
|
Or install directly:
|
|
@@ -32,13 +34,24 @@ WhoIsOnline.configure do |config|
|
|
|
32
34
|
config.ttl = 5.minutes
|
|
33
35
|
config.throttle = 60.seconds
|
|
34
36
|
config.user_id_method = :id
|
|
37
|
+
config.heartbeat_interval = 60.seconds # client heartbeat when tab visible
|
|
35
38
|
end
|
|
36
39
|
```
|
|
37
40
|
|
|
38
|
-
The engine auto-adds a concern that runs after each controller action to mark the `current_user` as online.
|
|
41
|
+
The engine auto-adds a concern that runs after each controller action to mark the `current_user` as online.
|
|
42
|
+
|
|
43
|
+
**To enable offline detection when users close their browser**, add this to your main layout (e.g., `app/views/layouts/application.html.erb`):
|
|
44
|
+
|
|
45
|
+
```erb
|
|
46
|
+
<%= whoisonline_offline_script %>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This will automatically mark users offline when they close the browser/tab.
|
|
50
|
+
Heartbeats run only when the tab is visible/active (interval: `heartbeat_interval`, default 60s), keeping the user online without constant polling.
|
|
39
51
|
|
|
40
52
|
## Public API
|
|
41
53
|
- `WhoIsOnline.track(user)` – mark a user online (auto-called by the controller concern).
|
|
54
|
+
- `WhoIsOnline.offline(user)` – mark a user offline immediately.
|
|
42
55
|
- `WhoIsOnline.online?(user)` – boolean.
|
|
43
56
|
- `WhoIsOnline.count` – number of online users (via SCAN).
|
|
44
57
|
- `WhoIsOnline.user_ids` – array of ids (strings by default).
|
|
@@ -52,6 +65,7 @@ WhoIsOnline.configure do |config|
|
|
|
52
65
|
config.throttle = 60.seconds # minimum time between Redis writes per user
|
|
53
66
|
config.user_id_method = :id # how to pull an ID from the user object
|
|
54
67
|
config.current_user_method = :current_user # method on controllers
|
|
68
|
+
config.heartbeat_interval = 60.seconds # heartbeat frequency while tab visible
|
|
55
69
|
config.namespace = "whoisonline:user"
|
|
56
70
|
config.auto_hook = true # disable if you prefer manual tracking
|
|
57
71
|
config.logger = Rails.logger if defined?(Rails)
|
|
@@ -69,6 +83,9 @@ end
|
|
|
69
83
|
# Somewhere in your controller you can also call manually:
|
|
70
84
|
WhoIsOnline.track(current_user)
|
|
71
85
|
|
|
86
|
+
# Mark user offline (e.g., on logout)
|
|
87
|
+
WhoIsOnline.offline(current_user)
|
|
88
|
+
|
|
72
89
|
# In a background job
|
|
73
90
|
if WhoIsOnline.online?(user)
|
|
74
91
|
# notify
|
|
@@ -79,6 +96,23 @@ end
|
|
|
79
96
|
@online_count = WhoIsOnline.count
|
|
80
97
|
```
|
|
81
98
|
|
|
99
|
+
### Layout Example
|
|
100
|
+
In your main layout (`app/views/layouts/application.html.erb`):
|
|
101
|
+
|
|
102
|
+
```erb
|
|
103
|
+
<!DOCTYPE html>
|
|
104
|
+
<html>
|
|
105
|
+
<head>
|
|
106
|
+
<title>My App</title>
|
|
107
|
+
<%= csrf_meta_tags %>
|
|
108
|
+
</head>
|
|
109
|
+
<body>
|
|
110
|
+
<%= yield %>
|
|
111
|
+
<%= whoisonline_offline_script %>
|
|
112
|
+
</body>
|
|
113
|
+
</html>
|
|
114
|
+
```
|
|
115
|
+
|
|
82
116
|
## Extensibility
|
|
83
117
|
- Engine-based hook is easy to extend (e.g., add ActionCable broadcast).
|
|
84
118
|
- Tracker service is isolated and unit-testable.
|
|
@@ -5,7 +5,7 @@ module WhoIsOnline
|
|
|
5
5
|
DEFAULT_NAMESPACE = "whoisonline:user".freeze
|
|
6
6
|
|
|
7
7
|
attr_accessor :ttl, :throttle, :user_id_method, :namespace, :auto_hook,
|
|
8
|
-
:logger, :current_user_method
|
|
8
|
+
:logger, :current_user_method, :heartbeat_interval
|
|
9
9
|
attr_writer :redis
|
|
10
10
|
|
|
11
11
|
def initialize
|
|
@@ -16,6 +16,7 @@ module WhoIsOnline
|
|
|
16
16
|
@namespace = DEFAULT_NAMESPACE
|
|
17
17
|
@auto_hook = true
|
|
18
18
|
@logger = default_logger
|
|
19
|
+
@heartbeat_interval = 60.seconds
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def redis
|
data/lib/whoisonline/engine.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "rails/engine"
|
|
2
2
|
require_relative "controller"
|
|
3
|
+
require_relative "presence_controller"
|
|
3
4
|
|
|
4
5
|
module WhoIsOnline
|
|
5
6
|
class Engine < ::Rails::Engine
|
|
@@ -10,6 +11,19 @@ module WhoIsOnline
|
|
|
10
11
|
include WhoIsOnline::Controller
|
|
11
12
|
end
|
|
12
13
|
end
|
|
14
|
+
|
|
15
|
+
initializer "whoisonline.routes" do |app|
|
|
16
|
+
app.routes.append do
|
|
17
|
+
post "/whoisonline/offline", to: "whoisonline/presence#offline", as: :whoisonline_offline
|
|
18
|
+
post "/whoisonline/heartbeat", to: "whoisonline/presence#heartbeat", as: :whoisonline_heartbeat
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
initializer "whoisonline.helpers" do
|
|
23
|
+
ActiveSupport.on_load(:action_view) do
|
|
24
|
+
include WhoIsOnline::ApplicationHelper
|
|
25
|
+
end
|
|
26
|
+
end
|
|
13
27
|
end
|
|
14
28
|
end
|
|
15
29
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require "action_controller"
|
|
2
|
+
|
|
3
|
+
module WhoIsOnline
|
|
4
|
+
class PresenceController < ActionController::Base
|
|
5
|
+
# Skip CSRF for sendBeacon requests (they may not include CSRF token reliably)
|
|
6
|
+
skip_before_action :verify_authenticity_token, raise: false
|
|
7
|
+
protect_from_forgery with: :null_session, only: [:offline]
|
|
8
|
+
|
|
9
|
+
def offline
|
|
10
|
+
user = resolve_whoisonline_user
|
|
11
|
+
WhoIsOnline.offline(user) if user
|
|
12
|
+
head :ok
|
|
13
|
+
rescue StandardError => e
|
|
14
|
+
WhoIsOnline.configuration.logger&.warn("whoisonline offline failed: #{e.class} #{e.message}")
|
|
15
|
+
head :ok
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def heartbeat
|
|
19
|
+
user = resolve_whoisonline_user
|
|
20
|
+
WhoIsOnline.track(user) if user
|
|
21
|
+
head :ok
|
|
22
|
+
rescue StandardError => e
|
|
23
|
+
WhoIsOnline.configuration.logger&.warn("whoisonline heartbeat failed: #{e.class} #{e.message}")
|
|
24
|
+
head :ok
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def resolve_whoisonline_user
|
|
30
|
+
method = WhoIsOnline.configuration.current_user_method
|
|
31
|
+
return public_send(method) if respond_to?(method, true)
|
|
32
|
+
|
|
33
|
+
nil
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
data/lib/whoisonline/tracker.rb
CHANGED
|
@@ -19,6 +19,15 @@ module WhoIsOnline
|
|
|
19
19
|
@last_write_by_user[uid] = Time.now if result
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
def offline(user)
|
|
23
|
+
uid = extract_id(user)
|
|
24
|
+
return unless uid
|
|
25
|
+
|
|
26
|
+
key = presence_key(uid)
|
|
27
|
+
@redis_store.delete_presence(key)
|
|
28
|
+
@last_write_by_user.delete(uid)
|
|
29
|
+
end
|
|
30
|
+
|
|
22
31
|
def online?(user)
|
|
23
32
|
uid = extract_id(user)
|
|
24
33
|
return false unless uid
|
data/lib/whoisonline/version.rb
CHANGED
data/lib/whoisonline.rb
CHANGED
|
@@ -10,7 +10,7 @@ require_relative "whoisonline/engine"
|
|
|
10
10
|
|
|
11
11
|
module WhoIsOnline
|
|
12
12
|
class << self
|
|
13
|
-
delegate :track, :online?, :count, :user_ids, :users, to: :tracker
|
|
13
|
+
delegate :track, :offline, :online?, :count, :user_ids, :users, to: :tracker
|
|
14
14
|
|
|
15
15
|
def tracker
|
|
16
16
|
@_tracker ||= Tracker.new(configuration, redis_store)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: whoisonline
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kapil Dev Pal
|
|
@@ -14,59 +14,59 @@ dependencies:
|
|
|
14
14
|
name: activesupport
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: '7.0'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '7.0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: railties
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
31
|
+
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
33
|
version: '7.0'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - "
|
|
38
|
+
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '7.0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: redis
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - "
|
|
45
|
+
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
47
|
version: '4.0'
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- - "
|
|
52
|
+
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '4.0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: concurrent-ruby
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- - "
|
|
59
|
+
- - ">="
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
61
|
version: '1.2'
|
|
62
62
|
type: :runtime
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
|
-
- - "
|
|
66
|
+
- - ">="
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '1.2'
|
|
69
|
-
description: Production-ready Rails 7
|
|
69
|
+
description: Production-ready Rails 7+ online presence tracking using Redis TTL and
|
|
70
70
|
controller auto-hook.
|
|
71
71
|
email:
|
|
72
72
|
- dev.kapildevpal@gmail.com
|
|
@@ -79,6 +79,7 @@ files:
|
|
|
79
79
|
- lib/whoisonline/configuration.rb
|
|
80
80
|
- lib/whoisonline/controller.rb
|
|
81
81
|
- lib/whoisonline/engine.rb
|
|
82
|
+
- lib/whoisonline/presence_controller.rb
|
|
82
83
|
- lib/whoisonline/redis_store.rb
|
|
83
84
|
- lib/whoisonline/tracker.rb
|
|
84
85
|
- lib/whoisonline/version.rb
|