mayu 0.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +69 -0
- data/LICENSE.txt +21 -0
- data/README.md +206 -0
- data/Rakefile +6 -0
- data/bin/mayu-association-collector +84 -0
- data/config.ru +41 -0
- data/lib/mayu.rb +8 -0
- data/lib/mayu/ap.rb +43 -0
- data/lib/mayu/app.rb +246 -0
- data/lib/mayu/association.rb +34 -0
- data/lib/mayu/cisco_wlc_collector.rb +102 -0
- data/lib/mayu/device.rb +23 -0
- data/lib/mayu/loader.rb +168 -0
- data/lib/mayu/map.rb +42 -0
- data/lib/mayu/periodic_loader.rb +55 -0
- data/lib/mayu/relation.rb +50 -0
- data/lib/mayu/renderer.rb +43 -0
- data/lib/mayu/stores/base.rb +44 -0
- data/lib/mayu/stores/concat.rb +41 -0
- data/lib/mayu/stores/file.rb +25 -0
- data/lib/mayu/stores/memory.rb +21 -0
- data/lib/mayu/stores/s3.rb +40 -0
- data/lib/mayu/user.rb +41 -0
- data/lib/mayu/user_completer.rb +30 -0
- data/lib/mayu/version.rb +3 -0
- data/mayu.gemspec +34 -0
- data/script/console +14 -0
- data/script/setup +8 -0
- metadata +176 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3c61048046382829176afa3f7fb6f7c5bfcbda14bf86d8e1bc9aa7249ee1bb52
|
4
|
+
data.tar.gz: 66e12c39eb042dbe1b5693bea135f1129c49e423e1d0c3e01aa6c1b75a4dc606
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f368f2c55b4d3d20a74b7d6e376a6df61d68281c6d33627bd470e75a52606bee7307a27409a54844f9feb3357a11dd850929b9838c7fbd76014146ad91cd2f03
|
7
|
+
data.tar.gz: 333ae0c533a8f749165716e446771cf273025685fc812a61225ac46a6c1f3932e75794057ef90ed1259002322729ac96f5c301a95881d84f3ec5d14ce80e9687
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in mayu.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
#gem 'graphed_fuzzy_search', path: File.expand_path('~/git/github.com/sorah/graphed_fuzzy_search')
|
9
|
+
gem 'puma'
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
mayu (0.1.0.beta1)
|
5
|
+
aws-sdk-s3
|
6
|
+
graphed_fuzzy_search
|
7
|
+
sinatra
|
8
|
+
wlc_snmp
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
aws-partitions (1.53.0)
|
14
|
+
aws-sdk-core (3.13.0)
|
15
|
+
aws-partitions (~> 1.0)
|
16
|
+
aws-sigv4 (~> 1.0)
|
17
|
+
jmespath (~> 1.0)
|
18
|
+
aws-sdk-kms (1.3.0)
|
19
|
+
aws-sdk-core (~> 3)
|
20
|
+
aws-sigv4 (~> 1.0)
|
21
|
+
aws-sdk-s3 (1.8.0)
|
22
|
+
aws-sdk-core (~> 3)
|
23
|
+
aws-sdk-kms (~> 1)
|
24
|
+
aws-sigv4 (~> 1.0)
|
25
|
+
aws-sigv4 (1.0.2)
|
26
|
+
diff-lcs (1.3)
|
27
|
+
graphed_fuzzy_search (0.1.0)
|
28
|
+
jmespath (1.3.1)
|
29
|
+
mustermann (1.0.1)
|
30
|
+
puma (3.11.0)
|
31
|
+
rack (2.0.3)
|
32
|
+
rack-protection (2.0.0)
|
33
|
+
rack
|
34
|
+
rake (12.3.0)
|
35
|
+
rspec (3.7.0)
|
36
|
+
rspec-core (~> 3.7.0)
|
37
|
+
rspec-expectations (~> 3.7.0)
|
38
|
+
rspec-mocks (~> 3.7.0)
|
39
|
+
rspec-core (3.7.0)
|
40
|
+
rspec-support (~> 3.7.0)
|
41
|
+
rspec-expectations (3.7.0)
|
42
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
43
|
+
rspec-support (~> 3.7.0)
|
44
|
+
rspec-mocks (3.7.0)
|
45
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
46
|
+
rspec-support (~> 3.7.0)
|
47
|
+
rspec-support (3.7.0)
|
48
|
+
sinatra (2.0.0)
|
49
|
+
mustermann (~> 1.0)
|
50
|
+
rack (~> 2.0)
|
51
|
+
rack-protection (= 2.0.0)
|
52
|
+
tilt (~> 2.0)
|
53
|
+
snmp (1.2.0)
|
54
|
+
tilt (2.0.8)
|
55
|
+
wlc_snmp (0.1.0)
|
56
|
+
snmp
|
57
|
+
|
58
|
+
PLATFORMS
|
59
|
+
ruby
|
60
|
+
|
61
|
+
DEPENDENCIES
|
62
|
+
bundler
|
63
|
+
mayu!
|
64
|
+
puma
|
65
|
+
rake
|
66
|
+
rspec (~> 3.0)
|
67
|
+
|
68
|
+
BUNDLED WITH
|
69
|
+
1.16.1
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Sorah Fukumori
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
# Mayu: Rack app to locate employees in an office by Wi-Fi MAC address and WLC association data
|
2
|
+
|
3
|
+
__UNDER DEVELOPMENT, just API works__
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'mayu'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install mayu
|
20
|
+
|
21
|
+
## Set up
|
22
|
+
|
23
|
+
### Components
|
24
|
+
|
25
|
+
1. Associaton collector: Collecting pair of MAC address => AP name
|
26
|
+
2. User collector: Collecting pair of MAC address => user information
|
27
|
+
3. Frontend: Web API and Frontend
|
28
|
+
|
29
|
+
This gem includes (1) for Cisco WLC and (3). About (2), you have to write your own script to generate JSON.
|
30
|
+
|
31
|
+
All data is stored in Amazon S3.
|
32
|
+
|
33
|
+
### Running associaton collector
|
34
|
+
|
35
|
+
```
|
36
|
+
bundle exec mayu-association-collector
|
37
|
+
```
|
38
|
+
|
39
|
+
- `--interval` (default: 60, env: `$MAYU_ASSOC_INTERVAL`): Interval in seconds to run updating.
|
40
|
+
- `--ttl` (default: 300, env: `$MAYU_ASSOC_TTL`): seconds to remove disappeared devices from list.
|
41
|
+
- `--wlc` (required, env: `$MAYU_ASSOC_WLC`): Address of WLC for SNMP communication
|
42
|
+
- `--community` (required, env: `$MAYU_ASSOC_WLC_COMMUNITY`): SNMP community of WLC
|
43
|
+
- `--use-ap-mac-for-key` (env: `$MAYU_ASSOC_AP_MAC_KEY`): Use MAC address of AP for identifying APs, instead of its name
|
44
|
+
- `--use-wlc-user` (env: `$MAYU_ASSOC_USE_WLC_USER`): Use username assigned by WLC for identifying user
|
45
|
+
- Choose either:
|
46
|
+
- File:
|
47
|
+
- `--output` (required, env: `$MAYU_ASSOC_FILE`)
|
48
|
+
- S3:
|
49
|
+
- `--s3-region` (required, env: `$MAYU_ASSOC_S3_REGION`)
|
50
|
+
- `--s3-bucket` (required, env: `$MAYU_ASSOC_S3_BUCKET`)
|
51
|
+
- `--s3-key` (required, env: `$MAYU_ASSOC_S3_KEY`)
|
52
|
+
|
53
|
+
### Running user collector
|
54
|
+
|
55
|
+
Write your own logic to collect your employees' device MAC addresses.
|
56
|
+
|
57
|
+
See [Internal](#internal) and place a properly formatted JSON file in S3.
|
58
|
+
|
59
|
+
### Running web frontend
|
60
|
+
|
61
|
+
```
|
62
|
+
bundle exec rackup
|
63
|
+
```
|
64
|
+
|
65
|
+
Run as a Rack app. Refer the bundled [config.ru](./config.ru)
|
66
|
+
|
67
|
+
The bundled config.ru accepts:
|
68
|
+
|
69
|
+
- `$MAYU_WEB_RELOAD_INTERVAL` (default: 60)
|
70
|
+
- `$MAYU_ASSOC_S3_REGION`
|
71
|
+
- `$MAYU_ASSOC_S3_BUCKET`
|
72
|
+
- `$MAYU_ASSOC_S3_KEY`
|
73
|
+
- `$MAYU_USER_S3_REGION`
|
74
|
+
- `$MAYU_USER_S3_BUCKET`
|
75
|
+
- `$MAYU_USER_S3_KEY`
|
76
|
+
|
77
|
+
Also, this app needs a list of APs for displaying a map.
|
78
|
+
|
79
|
+
- `$MAYU_AP_S3_REGION`
|
80
|
+
- `$MAYU_AP_S3_BUCKET`
|
81
|
+
- `$MAYU_AP_S3_KEY`
|
82
|
+
|
83
|
+
This JSON file should be formatted with a format in [Internal](#internal)
|
84
|
+
|
85
|
+
## Internal
|
86
|
+
|
87
|
+
### Formats
|
88
|
+
|
89
|
+
- All datetimes in a JSON should be formatted in ISO8601.
|
90
|
+
- MAC addresses should be formatted like `00:00:5e:00:53:a1` (hex, `:` separated, all lower case)
|
91
|
+
|
92
|
+
#### Association
|
93
|
+
|
94
|
+
``` json
|
95
|
+
{
|
96
|
+
"associations": [
|
97
|
+
{
|
98
|
+
"mac": "DEVICE_MAC",
|
99
|
+
"user_key": "USER",
|
100
|
+
"ap_key": "AP_KEY",
|
101
|
+
"updated_at": "UPDATED_AT",
|
102
|
+
"appeared_at": "APPEARED_AT",
|
103
|
+
"disappeared_at": "DISAPPEARED_AT"
|
104
|
+
}
|
105
|
+
]
|
106
|
+
}
|
107
|
+
```
|
108
|
+
|
109
|
+
- `DEVICE_MAC`: MAC address
|
110
|
+
- `USER` (optional): User key, if a user is determinable by an association. Otherwise user will be looked up from device MAC.
|
111
|
+
- `AP_KEY`: AP key (name, MAC address or anything. Key should be consistent among all other JSON files)
|
112
|
+
- `UPDATED_AT`: Time that this association updated.
|
113
|
+
- `APPEARED_AT`: Time that this association appeared.
|
114
|
+
- `DISAPPEARED_AT` (optional): Time that this association disappeared.
|
115
|
+
|
116
|
+
#### Users
|
117
|
+
|
118
|
+
``` json
|
119
|
+
{
|
120
|
+
"users": [
|
121
|
+
{
|
122
|
+
"key": "KEY",
|
123
|
+
"name": "NAME",
|
124
|
+
"aliases": ["ALIAS"],
|
125
|
+
"gravatar_email": "GRAVATAR_EMAIL"
|
126
|
+
}
|
127
|
+
],
|
128
|
+
"devices": [
|
129
|
+
{
|
130
|
+
"user_key": "USER_KEY",
|
131
|
+
"key": "DEVICE_KEY",
|
132
|
+
"mac": "DEVICE_MAC",
|
133
|
+
"kind": "DEVICE_KIND"
|
134
|
+
}
|
135
|
+
]
|
136
|
+
}
|
137
|
+
```
|
138
|
+
|
139
|
+
- `KEY`: Key (should be consistent among all other JSONs)
|
140
|
+
- `NAME`: Name
|
141
|
+
- `ALIAS` (optional): Alias (username, email, etc)
|
142
|
+
- `GRAVATAR_EMAIL` (optional): Gravatar email
|
143
|
+
- `DEVICE_MAC`: Device Wi-Fi MAC address that user owns.
|
144
|
+
- `DEVICE_KIND` (default: `other`): Kind of device (`pc`, `phone`, `tablet`, `other`)
|
145
|
+
|
146
|
+
#### APs
|
147
|
+
|
148
|
+
``` json
|
149
|
+
{
|
150
|
+
"maps": {
|
151
|
+
"MAP_KEY": {
|
152
|
+
"name": "MAP_NAME",
|
153
|
+
"url": "MAP_IMAGE_URL",
|
154
|
+
"fg_color": "HI_COLOR",
|
155
|
+
"bg_color": "HI_COLOR",
|
156
|
+
"highlight_color": "HI_COLOR"
|
157
|
+
}
|
158
|
+
},
|
159
|
+
"aps": {
|
160
|
+
"AP_KEY": {
|
161
|
+
"name": "AP_NAME",
|
162
|
+
"description": "AP_DESCRIPTION",
|
163
|
+
"map_key": "AP_MAP_KEY",
|
164
|
+
"map_x": "AP_MAP_X",
|
165
|
+
"map_y": "AP_MAP_Y"
|
166
|
+
}
|
167
|
+
}
|
168
|
+
}
|
169
|
+
```
|
170
|
+
|
171
|
+
- `MAP_KEY`: Key of map (should be consistent among other JSON files)
|
172
|
+
- `MAP_NAME`: Name of map (Floor name, etc)
|
173
|
+
- `MAP_IMAGE_URL`: Image URL
|
174
|
+
- `MAP_HI_COLOR`: Color for highlighting
|
175
|
+
- `AP_KEY`: AP key
|
176
|
+
- `AP_NAME`: Name of AP
|
177
|
+
- `AP_DESCRIPTION`: Description of AP (location information for human, etc)
|
178
|
+
- `AP_MAP_KEY`: Map corresponding for AP
|
179
|
+
- `AP_MAP_X`: X position of AP in map
|
180
|
+
- `AP_MAP_Y`: Y position of AP in map
|
181
|
+
|
182
|
+
### Relations
|
183
|
+
|
184
|
+
- user
|
185
|
+
- devices
|
186
|
+
- association
|
187
|
+
- association
|
188
|
+
- ap
|
189
|
+
- device
|
190
|
+
- map
|
191
|
+
- aps
|
192
|
+
- associations
|
193
|
+
|
194
|
+
## Development
|
195
|
+
|
196
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
197
|
+
|
198
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
199
|
+
|
200
|
+
## Contributing
|
201
|
+
|
202
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/sorah/mayu.
|
203
|
+
|
204
|
+
## License
|
205
|
+
|
206
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'mayu'
|
3
|
+
require 'optionparser'
|
4
|
+
|
5
|
+
$stdout.sync = true
|
6
|
+
|
7
|
+
interval = ENV.fetch('MAYU_ASSOC_INTERVAL', 60).to_i
|
8
|
+
options = {
|
9
|
+
ttl: ENV['MAYU_ASSOC_TTL']&.to_i,
|
10
|
+
host: ENV['MAYU_ASSOC_WLC'],
|
11
|
+
community: ENV['MAYU_ASSOC_WLC_COMMUNITY'],
|
12
|
+
ap_mac_for_key: ENV['MAYU_ASSOC_AP_MAC_KEY'],
|
13
|
+
use_wlc_user: ENV['MAYU_ASSOC_USE_WLC_USER'],
|
14
|
+
}.to_a.select { |k,v| v }.to_h
|
15
|
+
|
16
|
+
s3_options = {
|
17
|
+
region: ENV['MAYU_ASSOC_S3_REGION'],
|
18
|
+
bucket: ENV['MAYU_ASSOC_S3_BUCKET'],
|
19
|
+
key: ENV['MAYU_ASSOC_S3_KEY'],
|
20
|
+
}.to_a.select { |k,v| v }.to_h
|
21
|
+
file_options = {
|
22
|
+
path: ENV['MAYU_ASSOC_FILE']
|
23
|
+
}.to_a.select { |k,v| v }.to_h
|
24
|
+
|
25
|
+
OptionParser.new do |opt|
|
26
|
+
opt.on('-i SEC', '--interval SEC', 'interval between updates, in seconds') do |sec|
|
27
|
+
interval = sec.to_i
|
28
|
+
end
|
29
|
+
opt.on('-l TTL', '--ttl TTL', 'seconds to remove disappeared associations from list') do |sec|
|
30
|
+
options[:ttl] = sec.to_i
|
31
|
+
end
|
32
|
+
opt.on('-h HOST', '--wlc HOST', 'address of WLC for SNMP') do |host|
|
33
|
+
options[:host] = host
|
34
|
+
end
|
35
|
+
opt.on('-c COMMUNITY', '--community COMMUNITY', 'SNMP community') do |community|
|
36
|
+
options[:community] = community
|
37
|
+
end
|
38
|
+
opt.on('--use-ap-mac-for-key', 'Use AP MAC address for identifying APs') do
|
39
|
+
options[:ap_mac_for_key] = true
|
40
|
+
end
|
41
|
+
opt.on('--use-wlc-use', 'Use username assigned by WLC for identifying user') do
|
42
|
+
options[:use_wlc_user] = true
|
43
|
+
end
|
44
|
+
|
45
|
+
opt.on('-r REGION', '--s3-region REGION', 'S3 region') do |region|
|
46
|
+
s3_options[:s3_region] = true
|
47
|
+
end
|
48
|
+
opt.on('-b BUCKET', '--s3-bucket BUCKET', 'S3 bucket') do |bucket|
|
49
|
+
s3_options[:s3_bucket] = true
|
50
|
+
end
|
51
|
+
opt.on('-k KEY', '--s3-key KEY', 'S3 key') do |key|
|
52
|
+
s3_options[:s3_key] = key
|
53
|
+
end
|
54
|
+
|
55
|
+
opt.on('-o FILE', '--output FILE') do |path|
|
56
|
+
file_options[:path] = path
|
57
|
+
end
|
58
|
+
end.parse!(ARGV)
|
59
|
+
|
60
|
+
options[:store] = if file_options.empty?
|
61
|
+
Mayu::Stores::S3.new(**s3_options)
|
62
|
+
else
|
63
|
+
Mayu::Stores::File.new(**file_options)
|
64
|
+
end
|
65
|
+
|
66
|
+
collector_factory = lambda do
|
67
|
+
Mayu::CiscoWlcCollector.new(**options)
|
68
|
+
end
|
69
|
+
collector_factory.call # check for errors
|
70
|
+
|
71
|
+
loop do
|
72
|
+
puts '=> Updating...'
|
73
|
+
collector = collector_factory.call
|
74
|
+
collector.perform!
|
75
|
+
|
76
|
+
puts " * #{Time.now.xmlschema}: #{collector.associations.size} associations"
|
77
|
+
|
78
|
+
sleep interval
|
79
|
+
rescue SignalException, SystemExit => e
|
80
|
+
raise
|
81
|
+
rescue Exception => e
|
82
|
+
$stderr.puts e.full_message
|
83
|
+
sleep interval
|
84
|
+
end
|
data/config.ru
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'mayu'
|
2
|
+
|
3
|
+
stores = []
|
4
|
+
interval = ENV.fetch('MAYU_WEB_RELOAD_INTERVAL', 60).to_i
|
5
|
+
|
6
|
+
%w(ASSOC USER AP).each do |k|
|
7
|
+
if ENV["MAYU_#{k}_S3_REGION"] && ENV["MAYU_#{k}_S3_BUCKET"] && ENV["MAYU_#{k}_S3_KEY"]
|
8
|
+
regions = ENV["MAYU_#{k}_S3_REGION"].split(?;)
|
9
|
+
buckets = ENV["MAYU_#{k}_S3_BUCKET"].split(?;)
|
10
|
+
keys = ENV["MAYU_#{k}_S3_KEY"].split(?;)
|
11
|
+
regions.zip(buckets, keys).each do |region, bucket, key|
|
12
|
+
stores.push(
|
13
|
+
Mayu::Stores::S3.new(
|
14
|
+
region: region || regions.first,
|
15
|
+
bucket: bucket || buckets.first,
|
16
|
+
key: key || keys.first,
|
17
|
+
)
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
if ENV["MAYU_#{k}_FILE"]
|
22
|
+
files = ENV["MAYU_#{k}_FILE"].split(?;)
|
23
|
+
files.each do |file|
|
24
|
+
stores.push(
|
25
|
+
Mayu::Stores::File.new(
|
26
|
+
path: file,
|
27
|
+
)
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
store = Mayu::Stores::Concat.new(stores: stores)
|
34
|
+
loader = Mayu::Loader.new(store: store).load
|
35
|
+
#binding.irb
|
36
|
+
|
37
|
+
run Mayu.app(
|
38
|
+
store: store,
|
39
|
+
refresh_interval: interval,
|
40
|
+
slack_slash_command_token: ENV['MAYU_SLACK_SLASH_COMMAND_TOKEN'],
|
41
|
+
)
|