where_is_waldo 0.1.1
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 +7 -0
- data/CHANGELOG.md +43 -0
- data/LICENSE +21 -0
- data/README.md +467 -0
- data/VERSION +1 -0
- data/app/channels/where_is_waldo/application_cable/channel.rb +19 -0
- data/app/channels/where_is_waldo/application_cable/connection.rb +45 -0
- data/app/channels/where_is_waldo/jwt_connection.rb +83 -0
- data/app/channels/where_is_waldo/presence_channel.rb +86 -0
- data/app/channels/where_is_waldo/roster_channel.rb +52 -0
- data/app/jobs/where_is_waldo/application_job.rb +6 -0
- data/app/jobs/where_is_waldo/presence_cleanup_job.rb +13 -0
- data/app/models/concerns/where_is_waldo/broadcastable.rb +85 -0
- data/app/models/where_is_waldo/application_record.rb +7 -0
- data/app/models/where_is_waldo/presence.rb +87 -0
- data/app/services/where_is_waldo/adapters/base_adapter.rb +80 -0
- data/app/services/where_is_waldo/adapters/database_adapter.rb +104 -0
- data/app/services/where_is_waldo/adapters/redis_adapter.rb +205 -0
- data/app/services/where_is_waldo/broadcaster.rb +79 -0
- data/app/services/where_is_waldo/presence_service.rb +119 -0
- data/app/services/where_is_waldo/roster.rb +246 -0
- data/app/services/where_is_waldo/roster_delivery.rb +184 -0
- data/lib/generators/where_is_waldo/install/install_generator.rb +103 -0
- data/lib/generators/where_is_waldo/install/templates/channel.rb.tt +6 -0
- data/lib/generators/where_is_waldo/install/templates/connection.rb.tt +51 -0
- data/lib/generators/where_is_waldo/install/templates/create_presences.rb.tt +39 -0
- data/lib/generators/where_is_waldo/install/templates/initializer.rb.tt +37 -0
- data/lib/generators/where_is_waldo/install/templates/migration.rb.tt +20 -0
- data/lib/generators/where_is_waldo/install/templates/presence_channel.rb.tt +37 -0
- data/lib/where_is_waldo/configuration.rb +209 -0
- data/lib/where_is_waldo/engine.rb +17 -0
- data/lib/where_is_waldo/version.rb +5 -0
- data/lib/where_is_waldo.rb +117 -0
- metadata +249 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WhereIsWaldo
|
|
4
|
+
class Engine < ::Rails::Engine
|
|
5
|
+
isolate_namespace WhereIsWaldo
|
|
6
|
+
|
|
7
|
+
config.autoload_paths << File.expand_path("../../app/services", __dir__)
|
|
8
|
+
config.autoload_paths << File.expand_path("../../app/channels", __dir__)
|
|
9
|
+
config.autoload_paths << File.expand_path("../../app/jobs", __dir__)
|
|
10
|
+
config.autoload_paths << File.expand_path("../../app/models", __dir__)
|
|
11
|
+
|
|
12
|
+
# Configure Presence model associations after all code is loaded
|
|
13
|
+
config.after_initialize do
|
|
14
|
+
WhereIsWaldo::Presence.configure_associations! if WhereIsWaldo::Presence.respond_to?(:configure_associations!)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "where_is_waldo/version"
|
|
4
|
+
require "where_is_waldo/configuration"
|
|
5
|
+
require "where_is_waldo/engine" if defined?(Rails)
|
|
6
|
+
|
|
7
|
+
module WhereIsWaldo
|
|
8
|
+
class << self
|
|
9
|
+
def configuration
|
|
10
|
+
@configuration ||= Configuration.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def configure
|
|
14
|
+
yield(configuration)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def config
|
|
18
|
+
configuration
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def reset_configuration!
|
|
22
|
+
@configuration = Configuration.new
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# === Presence Management ===
|
|
26
|
+
|
|
27
|
+
def connect(...)
|
|
28
|
+
PresenceService.connect(...)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def disconnect(...)
|
|
32
|
+
PresenceService.disconnect(...)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def heartbeat(...)
|
|
36
|
+
PresenceService.heartbeat(...)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# === Queries ===
|
|
40
|
+
|
|
41
|
+
# Get online subjects from a scope
|
|
42
|
+
# @example WhereIsWaldo.online(org.members) => AR relation of online members
|
|
43
|
+
def online(scope, timeout: nil)
|
|
44
|
+
PresenceService.online(scope, timeout: timeout)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Get online subject IDs from a scope
|
|
48
|
+
# @example WhereIsWaldo.online_ids(org.members.admin)
|
|
49
|
+
def online_ids(scope, timeout: nil)
|
|
50
|
+
PresenceService.online_ids(scope, timeout: timeout)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Get all online subject IDs (no scope filtering)
|
|
54
|
+
def all_online_ids(timeout: nil)
|
|
55
|
+
PresenceService.all_online_ids(timeout: timeout)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
delegate :subject_online?, to: :PresenceService
|
|
59
|
+
|
|
60
|
+
delegate :sessions_for_subject, to: :PresenceService
|
|
61
|
+
|
|
62
|
+
delegate :session_status, to: :PresenceService
|
|
63
|
+
|
|
64
|
+
def cleanup(timeout: nil)
|
|
65
|
+
PresenceService.cleanup(timeout: timeout)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# === Presence roster (live presence awareness) ===
|
|
69
|
+
|
|
70
|
+
# Full roster state for an org record (every member + current presence).
|
|
71
|
+
def roster_snapshot(org, timeout: nil)
|
|
72
|
+
Roster.snapshot(org, timeout: timeout)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Aggregate presence state ({ status:, devices: }) for one subject.
|
|
76
|
+
def roster_state_for(subject_id, timeout: nil)
|
|
77
|
+
Roster.state_for(subject_id, timeout: timeout)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Presence status for a subject on a specific device/platform.
|
|
81
|
+
# @example WhereIsWaldo.presence_on(user.id, :mobile) # => "idle"
|
|
82
|
+
def presence_on(subject_id, platform, timeout: nil)
|
|
83
|
+
Roster.device_status(subject_id, platform, timeout: timeout)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Broadcast a compact presence delta for a subject to their org's roster
|
|
87
|
+
# stream. Call on transitions only (usually automatic via PresenceChannel).
|
|
88
|
+
def publish_presence(subject_id, timeout: nil)
|
|
89
|
+
Roster.publish(subject_id, timeout: timeout)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Shared roster stream name for the org a subject belongs to.
|
|
93
|
+
def roster_stream_for(subject)
|
|
94
|
+
Roster.stream_for_subject(subject)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# === Broadcasting ===
|
|
98
|
+
|
|
99
|
+
# Broadcast to subjects in a scope
|
|
100
|
+
# @example WhereIsWaldo.broadcast_to(org.members, :notification, { message: "Hello" })
|
|
101
|
+
def broadcast_to(scope, message_type, data = {})
|
|
102
|
+
Broadcaster.broadcast_to(scope, message_type, data)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Broadcast only to online subjects in a scope
|
|
106
|
+
# @example WhereIsWaldo.broadcast_to_online(org.members, :alert, { message: "Urgent" })
|
|
107
|
+
def broadcast_to_online(scope, message_type, data = {})
|
|
108
|
+
Broadcaster.broadcast_to_online(scope, message_type, data)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Broadcast to a specific session
|
|
112
|
+
# @example WhereIsWaldo.broadcast_to_session(session_id, :force_logout, { reason: "..." })
|
|
113
|
+
def broadcast_to_session(session_id, message_type, data = {})
|
|
114
|
+
Broadcaster.broadcast_to_session(session_id, message_type, data)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: where_is_waldo
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Scott Gibson
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-07-15 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '7.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '7.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: database_cleaner-active_record
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: factory_bot_rails
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '6.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '6.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: mock_redis
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0.36'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0.36'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: puma
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 7.2.1
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 7.2.1
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: redis
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '5.0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '5.0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rspec-rails
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '6.0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '6.0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: rubocop
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - "~>"
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '1.60'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - "~>"
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '1.60'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: rubocop-rails
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - "~>"
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '2.23'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - "~>"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '2.23'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: rubocop-rspec
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - "~>"
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '2.26'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - "~>"
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '2.26'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: sprockets-rails
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - "~>"
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: '3.4'
|
|
160
|
+
type: :development
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - "~>"
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: '3.4'
|
|
167
|
+
- !ruby/object:Gem::Dependency
|
|
168
|
+
name: sqlite3
|
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
|
170
|
+
requirements:
|
|
171
|
+
- - ">="
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '2.1'
|
|
174
|
+
type: :development
|
|
175
|
+
prerelease: false
|
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
177
|
+
requirements:
|
|
178
|
+
- - ">="
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: '2.1'
|
|
181
|
+
description: Track who's online, their activity state, and broadcast messages. Fully
|
|
182
|
+
configurable - works with any user model, session system, and room concept.
|
|
183
|
+
email:
|
|
184
|
+
- scott@byscott.io
|
|
185
|
+
executables: []
|
|
186
|
+
extensions: []
|
|
187
|
+
extra_rdoc_files: []
|
|
188
|
+
files:
|
|
189
|
+
- CHANGELOG.md
|
|
190
|
+
- LICENSE
|
|
191
|
+
- README.md
|
|
192
|
+
- VERSION
|
|
193
|
+
- app/channels/where_is_waldo/application_cable/channel.rb
|
|
194
|
+
- app/channels/where_is_waldo/application_cable/connection.rb
|
|
195
|
+
- app/channels/where_is_waldo/jwt_connection.rb
|
|
196
|
+
- app/channels/where_is_waldo/presence_channel.rb
|
|
197
|
+
- app/channels/where_is_waldo/roster_channel.rb
|
|
198
|
+
- app/jobs/where_is_waldo/application_job.rb
|
|
199
|
+
- app/jobs/where_is_waldo/presence_cleanup_job.rb
|
|
200
|
+
- app/models/concerns/where_is_waldo/broadcastable.rb
|
|
201
|
+
- app/models/where_is_waldo/application_record.rb
|
|
202
|
+
- app/models/where_is_waldo/presence.rb
|
|
203
|
+
- app/services/where_is_waldo/adapters/base_adapter.rb
|
|
204
|
+
- app/services/where_is_waldo/adapters/database_adapter.rb
|
|
205
|
+
- app/services/where_is_waldo/adapters/redis_adapter.rb
|
|
206
|
+
- app/services/where_is_waldo/broadcaster.rb
|
|
207
|
+
- app/services/where_is_waldo/presence_service.rb
|
|
208
|
+
- app/services/where_is_waldo/roster.rb
|
|
209
|
+
- app/services/where_is_waldo/roster_delivery.rb
|
|
210
|
+
- lib/generators/where_is_waldo/install/install_generator.rb
|
|
211
|
+
- lib/generators/where_is_waldo/install/templates/channel.rb.tt
|
|
212
|
+
- lib/generators/where_is_waldo/install/templates/connection.rb.tt
|
|
213
|
+
- lib/generators/where_is_waldo/install/templates/create_presences.rb.tt
|
|
214
|
+
- lib/generators/where_is_waldo/install/templates/initializer.rb.tt
|
|
215
|
+
- lib/generators/where_is_waldo/install/templates/migration.rb.tt
|
|
216
|
+
- lib/generators/where_is_waldo/install/templates/presence_channel.rb.tt
|
|
217
|
+
- lib/where_is_waldo.rb
|
|
218
|
+
- lib/where_is_waldo/configuration.rb
|
|
219
|
+
- lib/where_is_waldo/engine.rb
|
|
220
|
+
- lib/where_is_waldo/version.rb
|
|
221
|
+
homepage: https://github.com/byscott-io/where_is_waldo
|
|
222
|
+
licenses:
|
|
223
|
+
- MIT
|
|
224
|
+
metadata:
|
|
225
|
+
homepage_uri: https://github.com/byscott-io/where_is_waldo
|
|
226
|
+
source_code_uri: https://github.com/byscott-io/where_is_waldo
|
|
227
|
+
changelog_uri: https://github.com/byscott-io/where_is_waldo/blob/master/CHANGELOG.md
|
|
228
|
+
allowed_push_host: https://rubygems.org
|
|
229
|
+
rubygems_mfa_required: 'true'
|
|
230
|
+
post_install_message:
|
|
231
|
+
rdoc_options: []
|
|
232
|
+
require_paths:
|
|
233
|
+
- lib
|
|
234
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
235
|
+
requirements:
|
|
236
|
+
- - ">="
|
|
237
|
+
- !ruby/object:Gem::Version
|
|
238
|
+
version: 3.0.0
|
|
239
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
240
|
+
requirements:
|
|
241
|
+
- - ">="
|
|
242
|
+
- !ruby/object:Gem::Version
|
|
243
|
+
version: '0'
|
|
244
|
+
requirements: []
|
|
245
|
+
rubygems_version: 3.5.22
|
|
246
|
+
signing_key:
|
|
247
|
+
specification_version: 4
|
|
248
|
+
summary: Real-time presence tracking for Rails + React applications
|
|
249
|
+
test_files: []
|