debounced 0.1.16 → 0.1.19
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/lib/debounced/callback.rb +38 -0
- data/lib/debounced/javascript/server.mjs +2 -1
- data/lib/debounced/javascript/service.mjs +140 -0
- data/lib/debounced/service_proxy.rb +43 -65
- data/lib/debounced/version.rb +1 -1
- data/lib/debounced.rb +9 -5
- metadata +23 -37
- data/lib/debounced/javascript/debounce.mjs +0 -68
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5469038458279f90317b22acd88274c9a9cd5ddfe7d932e0fba6141230da1f65
|
4
|
+
data.tar.gz: 2776dc85b634f88d5f9ec7f4903de124a092455e25cffba08b91aaab903d7667
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9559170057bc4e13012e8d3d7234d1d2e2d1ed9eaa7100c8b2120b5c5b7b0d57cebfd4aa7e881b059bb9a6475b1dd45c4854467a883d09f7e88e159636faea4f
|
7
|
+
data.tar.gz: 5dadd3b4312c8985a2e3ad44b7aceb948250031bd9ca0e26da903211a42dc7a9ff0b26f57fa3e30062a05947c7738af6b999c809548a1781ccfe08176be0fb13
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'debug'
|
2
|
+
|
3
|
+
module Debounced
|
4
|
+
class Callback
|
5
|
+
|
6
|
+
attr_reader :class_name, :params, :method_name, :method_params
|
7
|
+
def initialize(class_name:, params:, method_name:, method_params:)
|
8
|
+
@class_name = class_name.to_s
|
9
|
+
@params = params || {}
|
10
|
+
@method_name = method_name.to_s
|
11
|
+
@method_params = method_params || []
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.json_create(data)
|
15
|
+
new(
|
16
|
+
class_name: data['class_name'],
|
17
|
+
params: data['params'],
|
18
|
+
method_name: data['method_name'],
|
19
|
+
method_params: data['method_params']
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def as_json
|
24
|
+
{
|
25
|
+
class_name:,
|
26
|
+
params:,
|
27
|
+
method_name:,
|
28
|
+
method_params:
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def call
|
33
|
+
Object.const_get(class_name)
|
34
|
+
.new(**params.transform_keys(&:to_sym))
|
35
|
+
.send(method_name, *method_params)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
2
|
|
3
|
-
import DebounceEventService from './
|
3
|
+
import DebounceEventService from './service.mjs'
|
4
4
|
let socketDescriptor = '/tmp/app.debounceEvents';
|
5
5
|
if (process.argv.length > 2) {
|
6
6
|
socketDescriptor = process.argv[2];
|
7
7
|
}
|
8
|
+
|
8
9
|
new DebounceEventService(socketDescriptor).listen();
|
@@ -0,0 +1,140 @@
|
|
1
|
+
import net from 'net';
|
2
|
+
import fs from 'fs';
|
3
|
+
|
4
|
+
export default class DebounceService {
|
5
|
+
constructor(socketDescriptor) {
|
6
|
+
this._socketDescriptor = socketDescriptor;
|
7
|
+
this._timers = {};
|
8
|
+
this._client = null;
|
9
|
+
this.publishEvent = this.publishEvent.bind(this);
|
10
|
+
this.debounceEvent = this.debounceEvent.bind(this);
|
11
|
+
this.reset = this.reset.bind(this);
|
12
|
+
this.listen = this.listen.bind(this);
|
13
|
+
this.handleError = this.handleError.bind(this);
|
14
|
+
this.onClientConnected = this.onClientConnected.bind(this);
|
15
|
+
this.onClientDisconnected = this.onClientDisconnected.bind(this);
|
16
|
+
this.onConnectionError = this.onConnectionError.bind(this);
|
17
|
+
this.handleMessage = this.handleMessage.bind(this);
|
18
|
+
this.configureServer();
|
19
|
+
}
|
20
|
+
|
21
|
+
onConnectionError(err) {
|
22
|
+
console.log('DebounceService client connection error');
|
23
|
+
this._client = null
|
24
|
+
this.handleError(err);
|
25
|
+
}
|
26
|
+
|
27
|
+
onClientDisconnected() {
|
28
|
+
console.log('DebounceService client disconnected');
|
29
|
+
this._client = null
|
30
|
+
}
|
31
|
+
|
32
|
+
handleMessage(message) {
|
33
|
+
try {
|
34
|
+
const object = JSON.parse(message);
|
35
|
+
if (object.type === 'debounceEvent') {
|
36
|
+
this.debounceEvent(object.data);
|
37
|
+
} else if (object.type === 'reset') {
|
38
|
+
this.reset();
|
39
|
+
} else {
|
40
|
+
console.log('DebounceService unknown message', message);
|
41
|
+
}
|
42
|
+
} catch (e) {
|
43
|
+
console.log('unable to parse message', e);
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
onClientConnected(socket) {
|
48
|
+
if (this._client) {
|
49
|
+
console.log('DebounceService rejecting connection: already has a client');
|
50
|
+
socket.end();
|
51
|
+
return;
|
52
|
+
}
|
53
|
+
|
54
|
+
console.log('DebounceService client connected');
|
55
|
+
let connectionBuffer = '';
|
56
|
+
this._client = socket;
|
57
|
+
socket.on('end', this.onClientDisconnected)
|
58
|
+
socket.on('error', this.onConnectionError)
|
59
|
+
socket.on('data', data => {
|
60
|
+
console.log('DebounceService data received', data.toString());
|
61
|
+
connectionBuffer += data.toString();
|
62
|
+
const messages = connectionBuffer.split('\f');
|
63
|
+
connectionBuffer = ''
|
64
|
+
if (!connectionBuffer.endsWith('\f')) {
|
65
|
+
connectionBuffer = messages.pop();
|
66
|
+
}
|
67
|
+
messages.forEach(this.handleMessage);
|
68
|
+
})
|
69
|
+
}
|
70
|
+
|
71
|
+
configureServer() {
|
72
|
+
this.server = net.createServer(this.onClientConnected)
|
73
|
+
this.server.on('error', this.handleError);
|
74
|
+
}
|
75
|
+
|
76
|
+
listen() {
|
77
|
+
// Remove the existing socket file if it exists
|
78
|
+
if (fs.existsSync(this._socketDescriptor)) {
|
79
|
+
console.log('DebounceEventService removing stale socket file ', this._socketDescriptor);
|
80
|
+
fs.unlinkSync(this._socketDescriptor);
|
81
|
+
}
|
82
|
+
|
83
|
+
process.on('exit', (code) => {
|
84
|
+
console.log(`Process exiting with code: ${code}`);
|
85
|
+
this.server.close();
|
86
|
+
});
|
87
|
+
|
88
|
+
process.on('SIGTERM', () => {
|
89
|
+
console.log('Process received SIGTERM');
|
90
|
+
this.server.close();
|
91
|
+
process.exit(0);
|
92
|
+
});
|
93
|
+
|
94
|
+
process.on('SIGINT', () => {
|
95
|
+
console.log('Process received SIGINT');
|
96
|
+
this.server.close();
|
97
|
+
process.exit(0);
|
98
|
+
});
|
99
|
+
|
100
|
+
this.server.listen(this._socketDescriptor, () => {
|
101
|
+
console.log('DebounceService listening on', this._socketDescriptor);
|
102
|
+
});
|
103
|
+
}
|
104
|
+
|
105
|
+
publishEvent(descriptor, callback) {
|
106
|
+
console.log(`Debounce period expired for ${descriptor}`);
|
107
|
+
const message = JSON.stringify({
|
108
|
+
type: 'publishEvent',
|
109
|
+
callback: callback
|
110
|
+
});
|
111
|
+
|
112
|
+
try {
|
113
|
+
this._client.write(message);
|
114
|
+
this._client.write("\f");
|
115
|
+
} catch (err) {
|
116
|
+
this.handleError(err);
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
debounceEvent({ descriptor, timeout, callback }) {
|
121
|
+
if (this._timers[descriptor]) {
|
122
|
+
clearTimeout(this._timers[descriptor]);
|
123
|
+
}
|
124
|
+
|
125
|
+
console.log("Debouncing", descriptor);
|
126
|
+
this._timers[descriptor] = setTimeout(() => {
|
127
|
+
delete this._timers[descriptor];
|
128
|
+
this.publishEvent(descriptor, callback);
|
129
|
+
}, timeout * 1000);
|
130
|
+
}
|
131
|
+
|
132
|
+
reset() {
|
133
|
+
Object.values(this._timers).forEach(timerID => clearTimeout(timerID));
|
134
|
+
this._timers = {};
|
135
|
+
}
|
136
|
+
|
137
|
+
handleError(err) {
|
138
|
+
console.log('\n\n######\nERROR: ', err);
|
139
|
+
}
|
140
|
+
}
|
@@ -1,7 +1,14 @@
|
|
1
1
|
require 'socket'
|
2
|
-
require '
|
2
|
+
require 'json'
|
3
|
+
require 'json/add/core'
|
4
|
+
require 'debug'
|
3
5
|
|
4
6
|
module Debounced
|
7
|
+
###
|
8
|
+
# Ruby interface to the debounce service
|
9
|
+
# Input is an activity descriptor, and an object.
|
10
|
+
# When the activity is debounced, a callback method is invoked on the object.
|
11
|
+
# Assumes the object class has an initializer that accepts a hash of attributes, which are the instance variables
|
5
12
|
class ServiceProxy
|
6
13
|
DELIMITER = "\f".freeze
|
7
14
|
|
@@ -11,16 +18,12 @@ module Debounced
|
|
11
18
|
|
12
19
|
def listen(abort_signal = nil)
|
13
20
|
Thread.new do
|
14
|
-
|
15
|
-
Rails.application.executor.wrap do
|
16
|
-
receive(abort_signal)
|
17
|
-
end
|
18
|
-
else
|
19
|
-
receive(abort_signal)
|
20
|
-
end
|
21
|
+
receive(abort_signal)
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
25
|
+
###
|
26
|
+
# Send message to server to reset its state. Useful for automated testing.
|
24
27
|
def reset
|
25
28
|
if socket.nil?
|
26
29
|
log_debug("No connection to #{server_name}; unable to reset server.")
|
@@ -30,13 +33,13 @@ module Debounced
|
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
33
|
-
def
|
36
|
+
def debounce_activity(activity_descriptor, timeout, callback)
|
34
37
|
if socket.nil?
|
35
|
-
log_debug("No connection to #{server_name};
|
36
|
-
|
38
|
+
log_debug("No connection to #{server_name}; skipping debounce step.")
|
39
|
+
callback.call
|
37
40
|
else
|
38
|
-
log_debug("
|
39
|
-
transmit(
|
41
|
+
log_debug("Debouncing #{activity_descriptor} to #{server_name}")
|
42
|
+
transmit(build_request(activity_descriptor, timeout, callback))
|
40
43
|
end
|
41
44
|
end
|
42
45
|
|
@@ -47,28 +50,32 @@ module Debounced
|
|
47
50
|
break if abort_signal&.set?
|
48
51
|
|
49
52
|
if socket.nil?
|
50
|
-
log_debug("Waiting for #{server_name}...")
|
53
|
+
log_debug("Waiting for #{server_name} to start...")
|
51
54
|
sleep(@wait_timeout)
|
52
55
|
next
|
53
56
|
end
|
54
57
|
|
58
|
+
log_debug("Waiting for data from #{server_name}...")
|
55
59
|
message = socket.gets(DELIMITER, chomp: true)
|
56
|
-
|
57
|
-
# gets => nil when server crashed.... try to reconnect
|
58
60
|
if message.nil?
|
61
|
+
log_info("Server #{server_name} ended connection")
|
59
62
|
close
|
60
|
-
|
63
|
+
break
|
61
64
|
end
|
62
65
|
|
66
|
+
log_debug("Received #{message}")
|
63
67
|
payload = deserialize_payload(message)
|
68
|
+
log_debug("Parsed #{payload}")
|
64
69
|
next unless payload['type'] == 'publishEvent'
|
65
70
|
|
66
|
-
|
71
|
+
instantiate_callback(payload['callback']).call
|
67
72
|
rescue IO::TimeoutError
|
68
|
-
# Ignored
|
73
|
+
# Ignored - normal flow of loop: check abort_signal (L48), get data (L56), timeout waiting for data (69)
|
69
74
|
end
|
70
75
|
rescue StandardError => e
|
71
76
|
log_warn("Unable to listen for messages from #{server_name}: #{e.message}")
|
77
|
+
log_warn(e.backtrace.join("\n"))
|
78
|
+
ensure
|
72
79
|
end
|
73
80
|
|
74
81
|
private
|
@@ -81,28 +88,17 @@ module Debounced
|
|
81
88
|
@socket = nil
|
82
89
|
end
|
83
90
|
|
84
|
-
def
|
91
|
+
def build_request(descriptor, timeout, callback)
|
85
92
|
{
|
86
93
|
type: 'debounceEvent',
|
87
94
|
data: {
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
attributes: event_attributes(event)
|
95
|
+
descriptor:,
|
96
|
+
timeout:,
|
97
|
+
callback: callback.as_json
|
92
98
|
}
|
93
99
|
}
|
94
100
|
end
|
95
101
|
|
96
|
-
def event_attributes(event)
|
97
|
-
if event.respond_to?(:attributes)
|
98
|
-
event.attributes
|
99
|
-
else
|
100
|
-
event.instance_variables.each_with_object({}) do |var, hash|
|
101
|
-
hash[var.to_s.delete('@')] = event.instance_variable_get(var)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
102
|
def transmit(request)
|
107
103
|
socket.send serialize_payload(request), 0
|
108
104
|
end
|
@@ -112,21 +108,15 @@ module Debounced
|
|
112
108
|
end
|
113
109
|
|
114
110
|
def serialize_payload(payload)
|
115
|
-
"#{
|
111
|
+
"#{JSON.generate(payload)}#{DELIMITER}" # inject EOM delimiter (form feed character)
|
116
112
|
end
|
117
113
|
|
118
114
|
def deserialize_payload(payload)
|
119
|
-
|
115
|
+
JSON.parse(payload)
|
120
116
|
end
|
121
117
|
|
122
|
-
def
|
123
|
-
|
124
|
-
end
|
125
|
-
|
126
|
-
def class_callback(data)
|
127
|
-
klass = data['klass'].constantize
|
128
|
-
data = data['attributes']
|
129
|
-
klass.send(Debounced.configuration.callback_method, data)
|
118
|
+
def instantiate_callback(data)
|
119
|
+
Callback.json_create(data)
|
130
120
|
end
|
131
121
|
|
132
122
|
def socket_descriptor
|
@@ -134,40 +124,28 @@ module Debounced
|
|
134
124
|
end
|
135
125
|
|
136
126
|
def socket
|
137
|
-
@socket ||=
|
138
|
-
|
139
|
-
|
127
|
+
@socket ||= begin
|
128
|
+
log_debug("Connecting to #{server_name} at #{socket_descriptor}")
|
129
|
+
UNIXSocket.new(socket_descriptor).tap { |s| s.timeout = @wait_timeout }
|
140
130
|
end
|
141
|
-
###
|
142
|
-
# Errno::ENOENT is raised if the socket file does not exist.
|
143
|
-
# Errno::ECONNREFUSED is raised if the socket file exists but no process is listening on it.
|
144
131
|
rescue Errno::ECONNREFUSED, Errno::ENOENT
|
132
|
+
###
|
133
|
+
# Errno::ENOENT is raised if the socket file does not exist.
|
134
|
+
# Errno::ECONNREFUSED is raised if the socket file exists but no process is listening on it.
|
145
135
|
log_debug("#{server_name} is not running")
|
146
136
|
nil
|
147
137
|
end
|
148
138
|
|
149
139
|
def log_debug(message)
|
150
|
-
|
151
|
-
Rails.logger.debug { message }
|
152
|
-
else
|
153
|
-
puts "[DEBUG] #{message}" if ENV['DEBUG']
|
154
|
-
end
|
140
|
+
Debounced.configuration.logger.debug { message }
|
155
141
|
end
|
156
142
|
|
157
143
|
def log_info(message)
|
158
|
-
|
159
|
-
Rails.logger.info(message)
|
160
|
-
else
|
161
|
-
puts "[INFO] #{message}"
|
162
|
-
end
|
144
|
+
Debounced.configuration.logger.info(message)
|
163
145
|
end
|
164
146
|
|
165
147
|
def log_warn(message)
|
166
|
-
|
167
|
-
Rails.logger.warn(message)
|
168
|
-
else
|
169
|
-
puts "[WARNING] #{message}"
|
170
|
-
end
|
148
|
+
Debounced.configuration.logger.warn(message)
|
171
149
|
end
|
172
150
|
end
|
173
151
|
end
|
data/lib/debounced/version.rb
CHANGED
data/lib/debounced.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require 'debounced/version'
|
2
|
+
require 'debounced/railtie' if defined?(Rails)
|
3
|
+
require 'debounced/service_proxy'
|
4
|
+
require 'debounced/callback'
|
5
|
+
require 'semantic_logger'
|
4
6
|
|
5
7
|
module Debounced
|
6
8
|
class Error < StandardError; end
|
@@ -16,12 +18,14 @@ module Debounced
|
|
16
18
|
end
|
17
19
|
|
18
20
|
class Configuration
|
19
|
-
attr_accessor :socket_descriptor, :wait_timeout, :
|
21
|
+
attr_accessor :socket_descriptor, :wait_timeout, :logger
|
20
22
|
|
21
23
|
def initialize
|
22
24
|
@socket_descriptor = ENV['DEBOUNCED_SOCKET'] || '/tmp/app.debounceEvents'
|
23
25
|
@wait_timeout = ENV['DEBOUNCED_TIMEOUT']&.to_i || 3
|
24
|
-
|
26
|
+
SemanticLogger.add_appender(file_name: 'debounced_proxy.log', formatter: :color)
|
27
|
+
SemanticLogger.default_level = ENV.fetch('LOG_LEVEL', 'info')
|
28
|
+
@logger = SemanticLogger['ServiceProxy']
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
metadata
CHANGED
@@ -1,92 +1,77 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: debounced
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.19
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gary Passero
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-03-
|
10
|
+
date: 2025-03-22 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
|
-
name:
|
13
|
+
name: json
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
16
|
- - "~>"
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version:
|
19
|
-
- - ">="
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: 7.0.0
|
18
|
+
version: 2.10.2
|
22
19
|
type: :runtime
|
23
20
|
prerelease: false
|
24
21
|
version_requirements: !ruby/object:Gem::Requirement
|
25
22
|
requirements:
|
26
23
|
- - "~>"
|
27
24
|
- !ruby/object:Gem::Version
|
28
|
-
version:
|
29
|
-
- - ">="
|
30
|
-
- !ruby/object:Gem::Version
|
31
|
-
version: 7.0.0
|
25
|
+
version: 2.10.2
|
32
26
|
- !ruby/object:Gem::Dependency
|
33
|
-
name:
|
27
|
+
name: semantic_logger
|
34
28
|
requirement: !ruby/object:Gem::Requirement
|
35
29
|
requirements:
|
36
30
|
- - "~>"
|
37
31
|
- !ruby/object:Gem::Version
|
38
|
-
version:
|
39
|
-
type: :
|
32
|
+
version: 4.15.0
|
33
|
+
type: :runtime
|
40
34
|
prerelease: false
|
41
35
|
version_requirements: !ruby/object:Gem::Requirement
|
42
36
|
requirements:
|
43
37
|
- - "~>"
|
44
38
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
39
|
+
version: 4.15.0
|
46
40
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
41
|
+
name: rspec
|
48
42
|
requirement: !ruby/object:Gem::Requirement
|
49
43
|
requirements:
|
50
44
|
- - "~>"
|
51
45
|
- !ruby/object:Gem::Version
|
52
|
-
version: '
|
46
|
+
version: '3.0'
|
53
47
|
type: :development
|
54
48
|
prerelease: false
|
55
49
|
version_requirements: !ruby/object:Gem::Requirement
|
56
50
|
requirements:
|
57
51
|
- - "~>"
|
58
52
|
- !ruby/object:Gem::Version
|
59
|
-
version: '
|
53
|
+
version: '3.0'
|
60
54
|
- !ruby/object:Gem::Dependency
|
61
|
-
name:
|
55
|
+
name: debug
|
62
56
|
requirement: !ruby/object:Gem::Requirement
|
63
57
|
requirements:
|
64
58
|
- - "~>"
|
65
59
|
- !ruby/object:Gem::Version
|
66
|
-
version: '
|
67
|
-
|
68
|
-
prerelease: false
|
69
|
-
version_requirements: !ruby/object:Gem::Requirement
|
70
|
-
requirements:
|
71
|
-
- - "~>"
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
version: '2.12'
|
74
|
-
- !ruby/object:Gem::Dependency
|
75
|
-
name: rubocop-rspec
|
76
|
-
requirement: !ruby/object:Gem::Requirement
|
77
|
-
requirements:
|
78
|
-
- - "~>"
|
60
|
+
version: '1.0'
|
61
|
+
- - ">="
|
79
62
|
- !ruby/object:Gem::Version
|
80
|
-
version:
|
63
|
+
version: 1.0.0
|
81
64
|
type: :development
|
82
65
|
prerelease: false
|
83
66
|
version_requirements: !ruby/object:Gem::Requirement
|
84
67
|
requirements:
|
85
68
|
- - "~>"
|
86
69
|
- !ruby/object:Gem::Version
|
87
|
-
version: '
|
88
|
-
|
89
|
-
|
70
|
+
version: '1.0'
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 1.0.0
|
74
|
+
description: Leverage JavaScript micro-event loop to debounce events in Ruby applications
|
90
75
|
email:
|
91
76
|
- gary@flytedesk.com
|
92
77
|
executables: []
|
@@ -97,8 +82,9 @@ files:
|
|
97
82
|
- README.md
|
98
83
|
- lib/debounced.rb
|
99
84
|
- lib/debounced/abort_signal.rb
|
100
|
-
- lib/debounced/
|
85
|
+
- lib/debounced/callback.rb
|
101
86
|
- lib/debounced/javascript/server.mjs
|
87
|
+
- lib/debounced/javascript/service.mjs
|
102
88
|
- lib/debounced/railtie.rb
|
103
89
|
- lib/debounced/service_proxy.rb
|
104
90
|
- lib/debounced/version.rb
|
@@ -1,68 +0,0 @@
|
|
1
|
-
import ipc from 'node-ipc';
|
2
|
-
import fs from 'fs';
|
3
|
-
|
4
|
-
const logLevel = process.env.LOG_LEVEL || 'info';
|
5
|
-
|
6
|
-
export default class DebounceService {
|
7
|
-
constructor(socketDescriptor) {
|
8
|
-
this._socketDescriptor = socketDescriptor;
|
9
|
-
this._timers = {};
|
10
|
-
this.publishEvent = this.publishEvent.bind(this);
|
11
|
-
this.debounceEvent = this.debounceEvent.bind(this);
|
12
|
-
this.reset = this.reset.bind(this);
|
13
|
-
this.listen = this.listen.bind(this);
|
14
|
-
this.handleError = this.handleError.bind(this);
|
15
|
-
this.configureServer();
|
16
|
-
this.registerMessageTypes();
|
17
|
-
}
|
18
|
-
|
19
|
-
registerMessageTypes() {
|
20
|
-
ipc.server.on('debounceEvent', this.debounceEvent);
|
21
|
-
ipc.server.on('reset', this.reset);
|
22
|
-
ipc.server.on('error', this.handleError);
|
23
|
-
}
|
24
|
-
|
25
|
-
configureServer() {
|
26
|
-
// Remove the existing socket file if it exists
|
27
|
-
if (fs.existsSync(this._socketDescriptor)) {
|
28
|
-
console.log('DebounceEventService removing stale socket file ', this._socketDescriptor);
|
29
|
-
fs.unlinkSync(this._socketDescriptor);
|
30
|
-
}
|
31
|
-
|
32
|
-
ipc.config.delimiter = '\f'; // incoming messages are terminated by a form feed character
|
33
|
-
ipc.config.encoding = 'utf8';
|
34
|
-
ipc.config.silent = (logLevel !== 'debug');
|
35
|
-
|
36
|
-
ipc.serve(this._socketDescriptor);
|
37
|
-
}
|
38
|
-
|
39
|
-
listen() {
|
40
|
-
console.log('DebounceService listening on', this._socketDescriptor);
|
41
|
-
ipc.server.start();
|
42
|
-
}
|
43
|
-
|
44
|
-
publishEvent(descriptor, data) {
|
45
|
-
console.log(`Debounce period expired for ${descriptor}, publishing ${data.klass} event`);
|
46
|
-
ipc.server.broadcast("publishEvent", data);
|
47
|
-
}
|
48
|
-
|
49
|
-
debounceEvent({ descriptor, attributes, klass, timeout }) {
|
50
|
-
if (this._timers[descriptor]) {
|
51
|
-
clearTimeout(this._timers[descriptor]);
|
52
|
-
}
|
53
|
-
|
54
|
-
this._timers[descriptor] = setTimeout(() => {
|
55
|
-
delete this._timers[descriptor];
|
56
|
-
this.publishEvent(descriptor, { attributes, klass });
|
57
|
-
}, timeout * 1000);
|
58
|
-
}
|
59
|
-
|
60
|
-
reset() {
|
61
|
-
Object.values(this._timers).forEach(timerID => clearTimeout(timerID));
|
62
|
-
this._timers = {};
|
63
|
-
}
|
64
|
-
|
65
|
-
handleError(err) {
|
66
|
-
console.log('\n\n######\nERROR: ', err);
|
67
|
-
}
|
68
|
-
}
|