feedx 0.6.2 → 0.6.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/Gemfile.lock +1 -1
- data/consumer.go +27 -10
- data/feedx.gemspec +1 -1
- data/lib/feedx/format.rb +21 -5
- data/producer.go +23 -12
- data/writer.go +12 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f4710e181ac3c987f7b02ebc976cf70bbc4c9826139823bca58620d94aa994a
|
4
|
+
data.tar.gz: 273951be43e9e8ac3473bfccf428cf2860c34dd4c0869b86f726446c477c2e7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 862eeb21fda2add182866fdb686adab45091d585a9880565b7e12c2ef3240ecc3982ec09e0370f1e4734d57ac44aa97cd5fcd702215c84d9534e5eab5ba9b648
|
7
|
+
data.tar.gz: fc10bdbfea9922ca29d3d0967ab8a1aa14330b914b1e07972ca61e040620d2ccdcd710e0eb63860001feb3c366097652b825fd4660e847449edfeecdbd3232e0
|
data/Gemfile.lock
CHANGED
data/consumer.go
CHANGED
@@ -17,8 +17,8 @@ type ConsumerOptions struct {
|
|
17
17
|
Interval time.Duration
|
18
18
|
|
19
19
|
// AfterSync callbacks are triggered after each sync, receiving
|
20
|
-
// the
|
21
|
-
AfterSync func(
|
20
|
+
// the sync state and error (if occurred).
|
21
|
+
AfterSync func(*ConsumerSync, error)
|
22
22
|
}
|
23
23
|
|
24
24
|
func (o *ConsumerOptions) norm(name string) error {
|
@@ -29,6 +29,18 @@ func (o *ConsumerOptions) norm(name string) error {
|
|
29
29
|
return nil
|
30
30
|
}
|
31
31
|
|
32
|
+
// ConsumerSync contains the state of the last sync.
|
33
|
+
type ConsumerSync struct {
|
34
|
+
// Consumer exposes the current consumer state.
|
35
|
+
Consumer
|
36
|
+
// Updated indicates is the sync resulted in an update.
|
37
|
+
Updated bool
|
38
|
+
// PreviousData references the data before the update.
|
39
|
+
// It allows to apply finalizers to data structures created by ConsumeFunc.
|
40
|
+
// This is only set when an update happened.
|
41
|
+
PreviousData interface{}
|
42
|
+
}
|
43
|
+
|
32
44
|
// ConsumeFunc is a parsing callback which is run by the consumer every sync interval.
|
33
45
|
type ConsumeFunc func(FormatDecoder) (data interface{}, err error)
|
34
46
|
|
@@ -137,7 +149,7 @@ func (c *consumer) Close() error {
|
|
137
149
|
return nil
|
138
150
|
}
|
139
151
|
|
140
|
-
func (c *consumer) sync(force bool) (
|
152
|
+
func (c *consumer) sync(force bool) (*ConsumerSync, error) {
|
141
153
|
defer func() {
|
142
154
|
atomic.StoreInt64(&c.lastSync, timestampFromTime(time.Now()).Millis())
|
143
155
|
}()
|
@@ -145,32 +157,37 @@ func (c *consumer) sync(force bool) (bool, error) {
|
|
145
157
|
// retrieve original last modified time
|
146
158
|
lastMod, err := remoteLastModified(c.ctx, c.remote)
|
147
159
|
if err != nil {
|
148
|
-
return
|
160
|
+
return nil, err
|
149
161
|
}
|
150
162
|
|
151
163
|
// skip update if not forced or modified
|
152
164
|
if lastMod.Millis() == atomic.LoadInt64(&c.lastMod) && !force {
|
153
|
-
return
|
165
|
+
return &ConsumerSync{Consumer: c}, nil
|
154
166
|
}
|
155
167
|
|
156
168
|
// open remote reader
|
157
169
|
reader, err := NewReader(c.ctx, c.remote, &c.opt.ReaderOptions)
|
158
170
|
if err != nil {
|
159
|
-
return
|
171
|
+
return nil, err
|
160
172
|
}
|
161
173
|
defer reader.Close()
|
162
174
|
|
163
175
|
// consume feed
|
164
176
|
data, err := c.cfn(reader)
|
165
177
|
if err != nil {
|
166
|
-
return
|
178
|
+
return nil, err
|
167
179
|
}
|
168
180
|
|
169
181
|
// update stores
|
182
|
+
previous := c.data.Load()
|
170
183
|
c.data.Store(data)
|
171
184
|
atomic.StoreInt64(&c.numRead, int64(reader.NumRead()))
|
172
185
|
atomic.StoreInt64(&c.lastMod, lastMod.Millis())
|
173
|
-
return
|
186
|
+
return &ConsumerSync{
|
187
|
+
Consumer: c,
|
188
|
+
Updated: true,
|
189
|
+
PreviousData: previous,
|
190
|
+
}, nil
|
174
191
|
}
|
175
192
|
|
176
193
|
func (c *consumer) loop() {
|
@@ -182,9 +199,9 @@ func (c *consumer) loop() {
|
|
182
199
|
case <-c.ctx.Done():
|
183
200
|
return
|
184
201
|
case <-ticker.C:
|
185
|
-
|
202
|
+
state, err := c.sync(false)
|
186
203
|
if c.opt.AfterSync != nil {
|
187
|
-
c.opt.AfterSync(
|
204
|
+
c.opt.AfterSync(state, err)
|
188
205
|
}
|
189
206
|
}
|
190
207
|
}
|
data/feedx.gemspec
CHANGED
data/lib/feedx/format.rb
CHANGED
@@ -5,6 +5,12 @@ module Feedx
|
|
5
5
|
autoload :Protobuf, 'feedx/format/protobuf'
|
6
6
|
|
7
7
|
class << self
|
8
|
+
def register(ext, kind)
|
9
|
+
raise ArgumentError, "#{kind} is not a subclass of Feedx::Format::Abstract" unless kind.is_a?(Class) && kind < Abstract
|
10
|
+
|
11
|
+
registry[ext.to_s] = kind
|
12
|
+
end
|
13
|
+
|
8
14
|
def resolve(name)
|
9
15
|
_resolve(name) || raise(ArgumentError, "invalid format #{name}")
|
10
16
|
end
|
@@ -24,13 +30,23 @@ module Feedx
|
|
24
30
|
|
25
31
|
private
|
26
32
|
|
33
|
+
def registry
|
34
|
+
@registry ||= {
|
35
|
+
'json' => :JSON,
|
36
|
+
'pb' => :Protobuf,
|
37
|
+
'proto' => :Protobuf,
|
38
|
+
'protobuf' => :Protobuf,
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
27
42
|
def _resolve(name)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
43
|
+
name = name.to_s
|
44
|
+
klass = registry[name]
|
45
|
+
if klass.is_a?(Symbol)
|
46
|
+
klass = const_get(klass)
|
47
|
+
registry[name.to_s] = klass
|
33
48
|
end
|
49
|
+
klass
|
34
50
|
end
|
35
51
|
end
|
36
52
|
end
|
data/producer.go
CHANGED
@@ -24,8 +24,8 @@ type ProducerOptions struct {
|
|
24
24
|
LastModCheck func(context.Context) (time.Time, error)
|
25
25
|
|
26
26
|
// AfterPush callbacks are triggered after each push cycle, receiving
|
27
|
-
// the
|
28
|
-
AfterPush func(
|
27
|
+
// the push state and error (if occurred).
|
28
|
+
AfterPush func(*ProducerPush, error)
|
29
29
|
}
|
30
30
|
|
31
31
|
func (o *ProducerOptions) norm(name string) error {
|
@@ -36,6 +36,14 @@ func (o *ProducerOptions) norm(name string) error {
|
|
36
36
|
return nil
|
37
37
|
}
|
38
38
|
|
39
|
+
// ProducerPush contains the state of the last push.
|
40
|
+
type ProducerPush struct {
|
41
|
+
// Producer exposes the current producer state.
|
42
|
+
*Producer
|
43
|
+
// Updated indicates is the push resulted in an update.
|
44
|
+
Updated bool
|
45
|
+
}
|
46
|
+
|
39
47
|
// Producer (continously) produces a feed.
|
40
48
|
type Producer struct {
|
41
49
|
remote *bfs.Object
|
@@ -120,7 +128,7 @@ func (p *Producer) Close() error {
|
|
120
128
|
return nil
|
121
129
|
}
|
122
130
|
|
123
|
-
func (p *Producer) push() (
|
131
|
+
func (p *Producer) push() (*ProducerPush, error) {
|
124
132
|
start := time.Now()
|
125
133
|
atomic.StoreInt64(&p.lastPush, timestampFromTime(start).Millis())
|
126
134
|
|
@@ -130,7 +138,7 @@ func (p *Producer) push() (bool, error) {
|
|
130
138
|
if p.opt.LastModCheck != nil {
|
131
139
|
modTime, err := p.opt.LastModCheck(p.ctx)
|
132
140
|
if err != nil {
|
133
|
-
return
|
141
|
+
return nil, err
|
134
142
|
}
|
135
143
|
wopt.LastMod = modTime
|
136
144
|
}
|
@@ -138,31 +146,34 @@ func (p *Producer) push() (bool, error) {
|
|
138
146
|
// retrieve original last modified time
|
139
147
|
lastMod, err := remoteLastModified(p.ctx, p.remote)
|
140
148
|
if err != nil {
|
141
|
-
return
|
149
|
+
return nil, err
|
142
150
|
}
|
143
151
|
|
144
152
|
// skip push if not modified
|
145
153
|
if lastMod.Time().Equal(wopt.LastMod) {
|
146
|
-
return
|
154
|
+
return &ProducerPush{Producer: p}, nil
|
147
155
|
}
|
148
156
|
|
149
157
|
writer, err := NewWriter(p.ctx, p.remote, &wopt)
|
150
158
|
if err != nil {
|
151
|
-
return
|
159
|
+
return nil, err
|
152
160
|
}
|
153
161
|
defer writer.Discard()
|
154
162
|
|
155
163
|
if err := p.pfn(writer); err != nil {
|
156
|
-
return
|
164
|
+
return nil, err
|
157
165
|
}
|
158
166
|
|
159
167
|
if err := writer.Commit(); err != nil {
|
160
|
-
return
|
168
|
+
return nil, err
|
161
169
|
}
|
162
170
|
|
163
171
|
atomic.StoreInt64(&p.numWritten, int64(writer.NumWritten()))
|
164
172
|
atomic.StoreInt64(&p.lastMod, timestampFromTime(wopt.LastMod).Millis())
|
165
|
-
return
|
173
|
+
return &ProducerPush{
|
174
|
+
Producer: p,
|
175
|
+
Updated: true,
|
176
|
+
}, nil
|
166
177
|
}
|
167
178
|
|
168
179
|
func (p *Producer) loop() {
|
@@ -174,9 +185,9 @@ func (p *Producer) loop() {
|
|
174
185
|
case <-p.ctx.Done():
|
175
186
|
return
|
176
187
|
case <-ticker.C:
|
177
|
-
|
188
|
+
state, err := p.push()
|
178
189
|
if p.opt.AfterPush != nil {
|
179
|
-
p.opt.AfterPush(
|
190
|
+
p.opt.AfterPush(state, err)
|
180
191
|
}
|
181
192
|
}
|
182
193
|
}
|
data/writer.go
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
package feedx
|
2
2
|
|
3
3
|
import (
|
4
|
+
"bufio"
|
4
5
|
"context"
|
5
6
|
"fmt"
|
6
7
|
"io"
|
@@ -55,6 +56,7 @@ type Writer struct {
|
|
55
56
|
|
56
57
|
bw io.WriteCloser // bfs writer
|
57
58
|
cw io.WriteCloser // compression writer
|
59
|
+
ww *bufio.Writer
|
58
60
|
fe FormatEncoder
|
59
61
|
}
|
60
62
|
|
@@ -96,8 +98,12 @@ func (w *Writer) Encode(v interface{}) error {
|
|
96
98
|
w.cw = cw
|
97
99
|
}
|
98
100
|
|
101
|
+
if w.ww == nil {
|
102
|
+
w.ww = bufio.NewWriter(w.cw)
|
103
|
+
}
|
104
|
+
|
99
105
|
if w.fe == nil {
|
100
|
-
fe, err := w.opt.Format.NewEncoder(w.
|
106
|
+
fe, err := w.opt.Format.NewEncoder(w.ww)
|
101
107
|
if err != nil {
|
102
108
|
return err
|
103
109
|
}
|
@@ -131,6 +137,11 @@ func (w *Writer) Commit() error {
|
|
131
137
|
err = e
|
132
138
|
}
|
133
139
|
}
|
140
|
+
if w.ww != nil {
|
141
|
+
if e := w.ww.Flush(); e != nil {
|
142
|
+
err = e
|
143
|
+
}
|
144
|
+
}
|
134
145
|
if w.cw != nil {
|
135
146
|
if e := w.cw.Close(); e != nil {
|
136
147
|
err = e
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: feedx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Black Square Media Ltd
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-05-
|
11
|
+
date: 2019-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bfs
|