board-sse-linuxfr.org 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 925a0bf418e17a5510f79d790a3fa57a7447826f018f8e0ce3324915541c48b0
4
+ data.tar.gz: 59c5e8491520cc9aac3eeb1f2b604745da9d81941d2e5d1c5ec61bdc831bf5d7
5
+ SHA512:
6
+ metadata.gz: 3ccb985f2211d416c0f5da6074388f5493fed88a3a4404a2ac1936dca19b73c9f7ac518bb5faf58e4f610760568da79ceb6c05816b74bd1efa9a6389f00679e3
7
+ data.tar.gz: dc85525402ec6339c2237c9f612c3174ad642a55182e3c0f392a66e1bd5b0fc0db98c3b94b4af71ee56697218b5fd5a1603fcfa2307608c4b9e58941a1e3d26e
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "board-sse-linuxfr.org"
@@ -0,0 +1,35 @@
1
+ class BoardSseLinuxfrOrg
2
+ class Cache
3
+ CAPACITY = 10
4
+
5
+ class Entry < Array
6
+ def push(item)
7
+ super item
8
+ shift if size > CAPACITY
9
+ end
10
+
11
+ def from(id, &blk)
12
+ found = false
13
+ each do |item|
14
+ blk.call item if found
15
+ found ||= item.first == id
16
+ end
17
+ end
18
+ end
19
+
20
+ def initialize
21
+ @keys = Entry.new
22
+ @vals = Entry.new
23
+ end
24
+
25
+ def [](key)
26
+ n = @keys.index(key)
27
+ unless n
28
+ @keys.push key
29
+ @vals.push Entry.new
30
+ n = @keys.length - 1
31
+ end
32
+ @vals[n]
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ require "hiredis"
2
+ require "em-synchrony"
3
+ require "redis"
4
+ require "redis/connection/synchrony"
5
+ require "board-sse-linuxfr.org/cache"
6
+
7
+
8
+ class BoardSseLinuxfrOrg
9
+ class RedisPlugin
10
+ def initialize(address, port, config, status, logger)
11
+ logger.info "Initializing the Redis plugin"
12
+ @logger = logger
13
+ @chans = status[:channels] = Hash.new { |h,k| h[k] = EM::Channel.new }
14
+ @cache = status[:cache] = Cache.new
15
+ @redis = Redis.new(host: ENV['REDIS_HOST'] || "localhost", port: ENV['REDIS_PORT'] || 6379)
16
+ end
17
+
18
+ def run
19
+ EM.synchrony do
20
+ @redis.psubscribe("b/*") do |on|
21
+ on.psubscribe do |pattern, total|
22
+ @logger.info "Psubscribe to redis: #{pattern} (#{total})"
23
+ end
24
+
25
+ on.pmessage do |pattern, chan, msg|
26
+ _, chan, id = *chan.split('/')
27
+ @logger.info "New message: [#{chan.inspect}] #{id}. #{msg}"
28
+ [@chans, @cache].each do |storage|
29
+ storage[chan].push [id, msg]
30
+ end
31
+ end
32
+
33
+ on.punsubscribe do |pattern, total|
34
+ @logger.info "Punsubscribe to redis: #{pattern} (#{total})"
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ class BoardSseLinuxfrOrg
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,33 @@
1
+ require "goliath"
2
+ require "yajl"
3
+
4
+
5
+ class BoardSseLinuxfrOrg < Goliath::API
6
+ autoload :Cache, "board-sse-linuxfr.org/cache"
7
+ autoload :RedisPlugin, "board-sse-linuxfr.org/redis_plugin"
8
+ autoload :VERSION, "board-sse-linuxfr.org/version"
9
+
10
+ plugin RedisPlugin
11
+
12
+ def response(env)
13
+ env.logger.info "New client: #{env['PATH_INFO']}"
14
+ send_msg = ->(args) {
15
+ id, msg = *args
16
+ env.stream_send("data: #{args.last}\nid: #{args.first}\n\n")
17
+ env.stream_close if env['HTTP_X_REQUESTED_WITH']
18
+ }
19
+ event_id = env['HTTP_LAST_EVENT_ID']
20
+ chan_name = env['PATH_INFO'].split('/', 3).last
21
+ env['cache'] = status[:cache][chan_name]
22
+ env['chan'] = status[:channels][chan_name]
23
+ env['sid'] = env['chan'].subscribe &send_msg
24
+ env['timer'] = EM.add_periodic_timer(15) { env.stream_send "::\n\n" }
25
+ EM.next_tick { env['cache'].from(event_id, &send_msg) } if event_id
26
+ streaming_response(200, {'Content-Type' => 'text/event-stream'})
27
+ end
28
+
29
+ def on_close(env)
30
+ env['chan'].unsubscribe env['sid'] if env['sid']
31
+ env['timer'].cancel if env['timer']
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: board-sse-linuxfr.org
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Bruno Michel
8
+ - Adrien Dorsaz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2024-03-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: goliath
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.0'
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.7
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - "~>"
29
+ - !ruby/object:Gem::Version
30
+ version: '1.0'
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.7
34
+ - !ruby/object:Gem::Dependency
35
+ name: hiredis
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.4'
41
+ type: :runtime
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.4'
48
+ - !ruby/object:Gem::Dependency
49
+ name: redis
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: yajl-ruby
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.2'
69
+ type: :runtime
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ - !ruby/object:Gem::Dependency
77
+ name: minitest
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.3'
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.3'
90
+ description: |
91
+ Users of the LinuxFr.org website can chat on a space called the board (« la tribune » in french).
92
+ This Ruby daemon notifies the users when something is said with Server-Sent Event / EventSource.
93
+ email: adrien@adorsaz.ch
94
+ executables:
95
+ - board-sse-linuxfr.org
96
+ extensions: []
97
+ extra_rdoc_files: []
98
+ files:
99
+ - bin/board-sse-linuxfr.org
100
+ - lib/board-sse-linuxfr.org.rb
101
+ - lib/board-sse-linuxfr.org/cache.rb
102
+ - lib/board-sse-linuxfr.org/redis_plugin.rb
103
+ - lib/board-sse-linuxfr.org/version.rb
104
+ homepage: https://github.com/linuxfrorg/board-sse-linuxfr.org
105
+ licenses:
106
+ - AGPL-3.0-only
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubygems_version: 3.5.3
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Board for LinuxFr.org
127
+ test_files: []