feedx 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e5d88effb5a873a2cb2e16d4c7f824b824ef2f93bc306c500b3f97314b7d91c
4
- data.tar.gz: be78ba37f5869fc6c2e026f2c1809dd083e7a0d02a55f66be3e9d555a6c7dc58
3
+ metadata.gz: 1f4710e181ac3c987f7b02ebc976cf70bbc4c9826139823bca58620d94aa994a
4
+ data.tar.gz: 273951be43e9e8ac3473bfccf428cf2860c34dd4c0869b86f726446c477c2e7f
5
5
  SHA512:
6
- metadata.gz: 9dab374c591498c3a23a0f2fab33fc8268c3c6028205b83c5483a4ebe27e468f00b05dfeb1200b237f358997f1d01654bec61fc1bb6fdd5c89fe317dba1e562d
7
- data.tar.gz: 71d086bc0f43ef382e354c710badb8b0f10f3cab75dca6f79abda448add5115c2c82ab26ab9a4b503cab23960918fd768d4b505d3ebb4a66156341d334525de1
6
+ metadata.gz: 862eeb21fda2add182866fdb686adab45091d585a9880565b7e12c2ef3240ecc3982ec09e0370f1e4734d57ac44aa97cd5fcd702215c84d9534e5eab5ba9b648
7
+ data.tar.gz: fc10bdbfea9922ca29d3d0967ab8a1aa14330b914b1e07972ca61e040620d2ccdcd710e0eb63860001feb3c366097652b825fd4660e847449edfeecdbd3232e0
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- feedx (0.6.2)
4
+ feedx (0.6.3)
5
5
  bfs (>= 0.3.4)
6
6
 
7
7
  GEM
@@ -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 updated status and error (if occurred).
21
- AfterSync func(updated bool, consumer Consumer, err error)
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) (bool, error) {
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 false, err
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 false, nil
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 false, err
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 false, err
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 true, nil
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
- updated, err := c.sync(false)
202
+ state, err := c.sync(false)
186
203
  if c.opt.AfterSync != nil {
187
- c.opt.AfterSync(updated, c, err)
204
+ c.opt.AfterSync(state, err)
188
205
  }
189
206
  }
190
207
  }
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'feedx'
3
- s.version = '0.6.2'
3
+ s.version = '0.6.3'
4
4
  s.authors = ['Black Square Media Ltd']
5
5
  s.email = ['info@blacksquaremedia.com']
6
6
  s.summary = %(Exchange data between components via feeds)
@@ -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
- case name.to_s
29
- when 'pb', 'proto', 'protobuf'
30
- Protobuf
31
- when 'json'
32
- JSON
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
@@ -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 updated status and error (if occurred).
28
- AfterPush func(updated bool, consumer *Producer, err error)
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() (bool, error) {
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 false, err
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 false, err
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 false, nil
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 false, err
159
+ return nil, err
152
160
  }
153
161
  defer writer.Discard()
154
162
 
155
163
  if err := p.pfn(writer); err != nil {
156
- return false, err
164
+ return nil, err
157
165
  }
158
166
 
159
167
  if err := writer.Commit(); err != nil {
160
- return false, err
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 true, nil
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
- updated, err := p.push()
188
+ state, err := p.push()
178
189
  if p.opt.AfterPush != nil {
179
- p.opt.AfterPush(updated, p, err)
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.cw)
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.2
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-17 00:00:00.000000000 Z
11
+ date: 2019-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bfs