driq 0.2.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: beb5ee5b3d3bdf18dc5f0f228868d99aaa915f72b023d0054c38842730773be3
4
- data.tar.gz: 3d5b872a9d5e94e9ea7ffbb70764b312a484b9f66c3f2e55c9430ca4a80977ba
3
+ metadata.gz: 6b19bed9a7c00d3a975d83d18c05fc0506bda4a10298089bd7649e6e4284ff4a
4
+ data.tar.gz: 88bd1c8cfae747649ee1924bf6bc637b385d8b7f176f69130b2a90a17be08cba
5
5
  SHA512:
6
- metadata.gz: 21f8fcdead5170e9ddae226845bde6af3225fce7776cde26463f57eb45fa3c6ac04e278cbf2d82c2854e827ba3873a892a2a47d3614762f49229e70a59b5f0b8
7
- data.tar.gz: f83aed8ea7c7c7adefa6db38ad976f89f8d08a6e80911fc057adeef3033f5c644701cbd7c052708832359a447e6187303fac6d11c9a2f7b0ff92e10449ff80fd
6
+ metadata.gz: cfe39da41d8d14647b23d506e553b5e429c20bcb2daeba0b1294366554653afaceeda23e7e528c5d6e2cd5068de168bdb96b42c219b77a7fe928488da2967c26
7
+ data.tar.gz: a8d6162074a0e5f4669e24163159a0862a0e4363d2605586b65260239c438277a026992b93f6f0633db4cbcda23f21c49ac128d7ca944b15833fb12d9c4b97dd
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Masatoshi SEKI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/driq.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ["lib"]
24
24
 
25
25
  spec.add_development_dependency "test-unit", "~> 3.3"
26
- spec.add_development_dependency "bundler", "~> 1.17"
27
- spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "bundler", ">= 2.2.10"
27
+ spec.add_development_dependency "rake", "~> 12.3.3"
28
28
  spec.add_development_dependency "rspec", "~> 3.0"
29
29
  end
data/lib/driq.rb CHANGED
@@ -5,10 +5,11 @@ require "json"
5
5
  class Driq
6
6
  include MonitorMixin
7
7
 
8
- def initialize(max_size=100)
8
+ def initialize(size=100)
9
9
  super()
10
10
  @last = 0
11
- @max_size = max_size
11
+ @floor = size
12
+ @ceil = size * 2
12
13
  @list = []
13
14
  @event = new_cond
14
15
  @closed = false
@@ -18,14 +19,15 @@ class Driq
18
19
  synchronize do
19
20
  cell = [make_key, value]
20
21
  @list.push(cell)
22
+ @list = @list.last(@floor) if @list.size > @ceil
21
23
  @event.broadcast
22
24
  return cell.first
23
25
  end
24
26
  end
25
27
  alias push write
26
28
 
27
- def read(key)
28
- readpartial(key, 1).first
29
+ def read(key, timeout=nil)
30
+ readpartial(key, 1, timeout).first
29
31
  end
30
32
 
31
33
  def last(if_empty=nil)
@@ -38,18 +40,18 @@ class Driq
38
40
  @last
39
41
  end
40
42
 
41
- def readpartial(key, size)
43
+ def readpartial(key, size, timeout=nil)
42
44
  synchronize do
43
45
  key = @last unless key
44
46
  raise ClosedQueueError if @closed
45
47
  idx = seek(key)
46
48
  if idx.nil?
47
49
  key = @last
48
- @event.wait
50
+ @event.wait(timeout)
49
51
  idx = seek(key)
50
52
  end
51
53
  raise ClosedQueueError if @closed
52
- @list.slice(idx, size)
54
+ idx ? @list.slice(idx, size) : []
53
55
  end
54
56
  end
55
57
 
@@ -72,12 +74,38 @@ class Driq
72
74
  end
73
75
  end
74
76
 
77
+ class DriqDownstream < Driq
78
+ def initialize(upper, size=100)
79
+ super(size)
80
+ @upper = upper
81
+ Thread.new { download }
82
+ end
83
+
84
+ def write(value)
85
+ @upper.write(value)
86
+ end
87
+
88
+ def download
89
+ while true
90
+ ary = @upper.readpartial(@last, @ceil)
91
+ synchronize do
92
+ @list += ary
93
+ @list = @list.last(@floor) if @list.size > @ceil
94
+ @last = ary.last[0]
95
+ @event.broadcast
96
+ end
97
+ end
98
+ end
99
+ end
100
+
75
101
  class Driq
76
102
  class EventSource
77
- def initialize(driq = nil)
103
+ def initialize(driq = nil, timeout = 60)
78
104
  @driq = driq || Driq.new
105
+ @timeout = timeout
79
106
  end
80
107
  attr_reader :driq
108
+ attr_accessor :timeout
81
109
 
82
110
  def write(value)
83
111
  @driq.write([nil, value])
@@ -111,7 +139,7 @@ class Driq
111
139
  end
112
140
 
113
141
  def read(cursor)
114
- cursor, value = @driq.read(cursor)
142
+ cursor, value = @driq.read(cursor, @timeout) || [cursor, [:ping, 'keep']]
115
143
  return cursor, build_packet(cursor, value[0], value[1])
116
144
  end
117
145
  end
data/lib/driq/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Driq
2
- VERSION = "0.2.0"
2
+ VERSION = "0.4.3"
3
3
  end
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+
3
+ cd /home/pi/src/Driq/sample/co2
4
+ /usr/bin/ruby -I ../../../ruby-mh-z19/lib co2.rb
@@ -0,0 +1,125 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>CO2</title>
5
+ </head>
6
+ <style type="text/css" media="screen">
7
+ body {
8
+ font-family: Helvetica;
9
+ background: #FFFFFF;
10
+ color: #000000; 
11
+ }
12
+
13
+ #myChart {
14
+ position: relative;
15
+ height:300; width:150
16
+ }
17
+ </style>
18
+ <body>
19
+ <div class="head">
20
+ <h2>CO2 <span id="co2"></span></h2>
21
+ </div>
22
+ <div class="main">
23
+ <canvas id="myChart" style="position: relative; height:100; width:150"></canvas>
24
+ </div>
25
+
26
+ </body>
27
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
28
+ <script>
29
+
30
+ var evt = new EventSource('stream');
31
+
32
+ evt.onmessage = function(e) {
33
+ var it = JSON.parse(e.data);
34
+ console.log(it);
35
+ console.log(new Date(Number(e.lastEventId) * 0.001));
36
+ time = new Date(Number(e.lastEventId) * 0.001);
37
+ add_data(it['concentration'], it['temperature'], time);
38
+ };
39
+
40
+ var co2_text = document.getElementById("co2");
41
+
42
+ function add_data(concentration, temperature, time) {
43
+ chartDataSet.data.datasets[0].data.push({
44
+ y: concentration,
45
+ t: time
46
+ });
47
+ chartDataSet.data.datasets[1].data.push({
48
+ y: temperature,
49
+ t: time
50
+ });
51
+ while (time - chartDataSet.data.datasets[0].data[0].t > 3600000) {
52
+ chartDataSet.data.datasets[0].data.shift();
53
+ chartDataSet.data.datasets[1].data.shift();
54
+ }
55
+ chart.update();
56
+ co2_text.textContent = concentration + 'ppm';
57
+ document.title = concentration + 'ppm';
58
+ }
59
+
60
+ var ctx = document.getElementById("myChart").getContext('2d');
61
+ const chartDataSet = {
62
+ type: 'line',
63
+ responsive: false,
64
+ aspectRatio: 2,
65
+ data: {
66
+ datasets: [{
67
+ label: 'ppm',
68
+ data: [],
69
+ borderColor: "rgb(54, 162, 235)",
70
+ fill: false,
71
+ yAxisID: "y-axis-1"
72
+ }, {
73
+ label: 'temp',
74
+ data: [],
75
+ borderColor: "rgb(235, 0, 0)",
76
+ fill: false,
77
+ yAxisID: "y-axis-2"
78
+ }]
79
+ },
80
+ options: {
81
+ scales: {
82
+ xAxes: [{
83
+ type: 'time',
84
+ time: {
85
+ displayFormats: {
86
+ millisecond: 'h:mm',
87
+ second: 'h:mm',
88
+ minute: 'h:mm'
89
+ },
90
+ unit: 'minute'
91
+ },
92
+ distribution: 'linear',
93
+ ticks: {
94
+ maxTicksLimit:6,
95
+ source: 'data'
96
+ },
97
+ gridLines: {
98
+ display: false
99
+ }
100
+ }],
101
+ yAxes: [{
102
+ id: 'y-axis-1',
103
+ ticks: {
104
+ source: 'data',
105
+ min: 200,
106
+ max: 2000
107
+ }
108
+ }, {
109
+ id: 'y-axis-2',
110
+ position: 'right',
111
+ ticks: {
112
+ source: 'data',
113
+ min: -5,
114
+ max: 40
115
+ },
116
+ gridLines: {
117
+ display: false
118
+ }
119
+ }]
120
+ }
121
+ }
122
+ };
123
+ var chart = new Chart(ctx, chartDataSet);
124
+ </script>
125
+ </html>
data/sample/co2/co2.rb ADDED
@@ -0,0 +1,60 @@
1
+ require 'webrick'
2
+ require 'driq'
3
+ require 'driq/webrick'
4
+ require 'mh-z19'
5
+
6
+ class CO2
7
+ def initialize(port)
8
+ @src = Driq::EventSource.new
9
+ @svr = WEBrick::HTTPServer.new(:Port => port)
10
+
11
+ @svr.mount_proc('/') do |req, res|
12
+ on_index(req, res)
13
+ end
14
+
15
+ @svr.mount_proc('/stream') do |req, res|
16
+ on_stream(req, res)
17
+ end
18
+
19
+ @front = {"src" => @src,
20
+ "webrick" => @svr,
21
+ "body" => File.read('co2.html')}
22
+ end
23
+
24
+ def on_index(req, res)
25
+ res.body = File.read("co2.html")
26
+ end
27
+
28
+ def on_stream(req, res)
29
+ last_event_id = req["Last-Event-ID"] || 0
30
+ res.content_type = 'text/event-stream'
31
+ res.chunked = true
32
+ res.body = WEBrick::ChunkedStream.new(Driq::EventStream.new(@src, last_event_id))
33
+ end
34
+
35
+ def start
36
+ Thread.new { co2_loop }
37
+ @svr.start
38
+ end
39
+
40
+ def co2_loop
41
+ co2 = MH_Z19::Serial.new('/dev/serial0')
42
+ last = nil
43
+ sleep 3
44
+ loop do
45
+ begin
46
+ detail = co2.read_concentration_detail rescue nil
47
+ @src.write(detail) unless last == detail
48
+ last = detail
49
+ rescue MH_Z19::Serial::InvalidPacketException
50
+ p $!
51
+ end
52
+ sleep 60
53
+ end
54
+ end
55
+ end
56
+
57
+ port = Integer(ENV['PORT']) rescue 8080
58
+
59
+ co2 = CO2.new(port)
60
+ co2.start
@@ -0,0 +1,16 @@
1
+ #
2
+
3
+ [Unit]
4
+ Description=MH-Z14A CO2 Server
5
+ After=network.target
6
+ After=syslog.target
7
+
8
+ [Install]
9
+ WantedBy=multi-user.target
10
+
11
+ [Service]
12
+ User=pi
13
+ Group=pi
14
+ Type=simple
15
+ ExecStart=/home/pi/src/Driq/sample/co2/co2-service.sh
16
+ Restart=always
@@ -0,0 +1,85 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Koto</title>
5
+ </head>
6
+ <style type="text/css" media="screen">
7
+ body {
8
+ font-family: Helvetica;
9
+ background: #FFFFFF;
10
+ color: #000000; 
11
+ }
12
+
13
+ .EnterTofu input {
14
+ box-sizing: border-box;
15
+ width: 100%;
16
+ padding: 16px 6px 6px 6px;
17
+ font-size: 16px;
18
+ font-weight: normal;
19
+ background: #6d84a2;
20
+ }
21
+
22
+ .ListTofu > ul {
23
+ margin: 0;
24
+ padding: 0;
25
+ }
26
+
27
+ .ListTofu > ul > li {
28
+ border-bottom: 1px solid #E0E0E0;
29
+ padding: 8px 0 8px 10px;
30
+ font-size: 14px;
31
+ font-weight: bold;
32
+ list-style: none:
33
+ }
34
+
35
+ .ListTofu > ul > li.group {
36
+ top: -1px;
37
+ margin-bottom: -2px;
38
+ border-top: 1px solid #7d7d7d;
39
+ border-bottom: 1px solid #999999;
40
+ padding: 1px 5px;
41
+ font-size: 13px;
42
+ font-weight: bold;
43
+ text-shadow: rgba(0, 0, 0, 0.4) 0 1px 0;
44
+ color: #FFFFFF;
45
+ }
46
+ </style>
47
+ <body>
48
+ <div class="EnterTofu">
49
+ <input id='enter' type='text' size='40' name='str' value='' autocomplete='off' autofocus onchange="postNews();"/>
50
+ </div>
51
+ <div class="ListTofu">
52
+ <ul id="list">
53
+ </ul>
54
+ </div>
55
+ </body>
56
+ <script>
57
+ var evt = new EventSource('stream');
58
+ var input = document.querySelector("#enter");
59
+ var eventList = document.getElementById('list');
60
+
61
+ evt.onmessage = function(e) {
62
+ var entry = JSON.parse(e.data);
63
+
64
+ var newString = document.createElement("li");
65
+ newString.textContent = entry["text"];
66
+
67
+ var newGroup = document.createElement("li");
68
+ newGroup.textContent = entry["group"];
69
+ newGroup.classList.add("group");
70
+ newGroup.style.color = entry["color"];
71
+
72
+ eventList.prepend(newGroup, newString);
73
+
74
+ document.title = entry["text"];
75
+ };
76
+
77
+ function postNews() {
78
+ var xhr = new XMLHttpRequest();
79
+ xhr.open("POST", "news");
80
+ xhr.setRequestHeader("Content-Type", "application/json");
81
+ xhr.send(JSON.stringify({"text": input.value}));
82
+ input.value = "";
83
+ }
84
+ </script>
85
+ </html>
@@ -0,0 +1,74 @@
1
+ require 'webrick'
2
+ require 'driq'
3
+ require 'driq/webrick'
4
+ require 'drb'
5
+ require 'digest/md5'
6
+
7
+ class Koto
8
+ def initialize(port, drb_url)
9
+ @src = Driq::EventSource.new
10
+ @svr = WEBrick::HTTPServer.new(:Port => port)
11
+
12
+ @svr.mount_proc('/') do |req, res|
13
+ on_index(req, res)
14
+ end
15
+
16
+ @svr.mount_proc('/stream') do |req, res|
17
+ on_stream(req, res)
18
+ end
19
+
20
+ @svr.mount_proc('/news') do |req, res|
21
+ on_news(req, res)
22
+ end
23
+
24
+ @front = {"src" => @src,
25
+ "webrick" => @svr,
26
+ "body" => File.read('koto.html')}
27
+ DRb.start_service(drb_url, @front)
28
+ end
29
+
30
+ def on_index(req, res)
31
+ res.body = @front["body"]
32
+ end
33
+
34
+ def on_stream(req, res)
35
+ last_event_id = req["Last-Event-ID"] || 0
36
+ res.content_type = 'text/event-stream'
37
+ res.chunked = true
38
+ res.body = WEBrick::ChunkedStream.new(Driq::EventStream.new(@src, last_event_id))
39
+ end
40
+
41
+ def on_news(req, res)
42
+ it = make_entry(req)
43
+ @src.write(it)
44
+ res.content_type = "text/plain"
45
+ res.body = "i know";
46
+ end
47
+
48
+ Color = Hash.new do |h, k|
49
+ md5 = Digest::MD5.new
50
+ md5 << k.to_s
51
+ r = 0b01111111 & md5.digest[0].unpack("c").first
52
+ g = 0b01111111 & md5.digest[1].unpack("c").first
53
+ b = 0b01111111 & md5.digest[2].unpack("c").first
54
+ h[k] = sprintf("#%02x%02x%02x", r, g, b)
55
+ end
56
+
57
+ def make_entry(req)
58
+ text = JSON.parse(req.body)["text"] || ""
59
+ from = req["X-Forwarded-For"] || req.peeraddr[2]
60
+ color = Color[from]
61
+ group = [from, Time.now.strftime("%H:%M")].join(" @ ")
62
+ {"text" => text, "group" => group, "color" => color}
63
+ end
64
+
65
+ def start
66
+ @svr.start
67
+ end
68
+ end
69
+
70
+ port = Integer(ENV['TOFU_PORT']) rescue 10510
71
+ drb_url = 'druby://localhost:55443'
72
+
73
+ koto = Koto.new(port, drb_url)
74
+ koto.start
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: driq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masatoshi SEKI
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-03 00:00:00.000000000 Z
11
+ date: 2021-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-unit
@@ -28,30 +28,30 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.17'
33
+ version: 2.2.10
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '1.17'
40
+ version: 2.2.10
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: 12.3.3
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: 12.3.3
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -75,12 +75,19 @@ extra_rdoc_files: []
75
75
  files:
76
76
  - ".gitignore"
77
77
  - Gemfile
78
+ - LICENSE
78
79
  - README.md
79
80
  - Rakefile
80
81
  - driq.gemspec
81
82
  - lib/driq.rb
82
83
  - lib/driq/version.rb
83
84
  - lib/driq/webrick.rb
85
+ - sample/co2/co2-service.sh
86
+ - sample/co2/co2.html
87
+ - sample/co2/co2.rb
88
+ - sample/co2/co2.service
89
+ - sample/koto/koto.html
90
+ - sample/koto/koto.rb
84
91
  homepage: https://github.com/seki/Driq
85
92
  licenses: []
86
93
  metadata: {}
@@ -99,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
106
  - !ruby/object:Gem::Version
100
107
  version: '0'
101
108
  requirements: []
102
- rubygems_version: 3.1.2
109
+ rubygems_version: 3.2.3
103
110
  signing_key:
104
111
  specification_version: 4
105
112
  summary: simple rd-stream