nutella_framework 0.4.0 → 0.4.1
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 +1 -2
- data/README.md +11 -11
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/framework_components/runs_list_bot/app_runs_list_bot.rb +45 -9
- data/framework_components/runs_list_bot/startup +8 -0
- data/lib/commands/start.rb +3 -0
- data/lib/config/current_app_utils.rb +7 -1
- data/lib/config/runlist.rb +12 -3
- data/nutella_framework.gemspec +11 -12
- data/nutella_lib/framework_core.rb +68 -0
- data/{lib/nutella_lib_framework/api.rb → nutella_lib/framework_net.rb} +205 -43
- data/test/framework_apis/test_framework_api.rb +1 -1
- metadata +11 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ee0147d7ad4b06c602ad742ad464804686a73af
|
4
|
+
data.tar.gz: 5255b9ac953ca5d4a2608943ed6d7fab61cebaaf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e93582f785ccdebe69dd852033edd700935bc957a29844633d07d7001459d928e0b20b1d72f9740e67941a68c3fca1ab67f871ac2c9b3a1c8288fe540fe593f6
|
7
|
+
data.tar.gz: 23ac44867911110658384dce2379c8a3336868ce39e7f8cec1d07ff07ed04fb3a2790c22186d218f6cfe39e1e36ccf41c301a95953e340c174f957e21b6fa969
|
data/Gemfile
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gem 'ansi', '~> 1.4', '>= 1.4.3'
|
4
3
|
gem 'semantic', '~> 1.3', '>=1.3'
|
5
4
|
gem 'logging', '~> 1.8', '>=1.8.2'
|
6
5
|
gem 'git', '~> 1.2', '>=1.2.8'
|
@@ -8,7 +7,7 @@ gem 'sinatra', '~>1.4.5', '>=1.4.5'
|
|
8
7
|
gem 'thin', '~>1.6.3', '>=1.6.3'
|
9
8
|
gem 'nokogiri', '~>1.6.3', '>=1.6.3'
|
10
9
|
gem 'slop', '~>4.0.0', '>=4.0.0'
|
11
|
-
gem 'nutella_lib','~>0.4.
|
10
|
+
gem 'nutella_lib','~>0.4.1', '>=0.4.1'
|
12
11
|
|
13
12
|
|
14
13
|
group :development do
|
data/README.md
CHANGED
@@ -3,18 +3,18 @@
|
|
3
3
|
[](https://travis-ci.org/nutella-framework/nutella_framework)
|
4
4
|
[](https://codeclimate.com/github/nutella-framework/nutella_framework)
|
5
5
|
|
6
|
-
|
7
|
-
Nutella is a framework to build and run classroom narratives. It's still _very_ under development so any help [finding and fixing bugs](https://github.com/nutella-framework/nutella_framework/issues) will be greatly appreciated!
|
6
|
+
nutella is a framework to build and run RoomApps. It's still _very_ under development so any help [finding and fixing bugs](https://github.com/nutella-framework/nutella_framework/issues) will be greatly appreciated!
|
8
7
|
|
9
8
|
# Installing
|
10
|
-
Nutella is written in ruby but it leverages
|
9
|
+
Nutella is written in ruby but it leverages a bunch of other technologies that need to be installed. You will need:
|
11
10
|
|
12
|
-
1. _ruby_ (version >= 2.1.0). Do yourself a favor and use [RVM](https://rvm.io/rvm/install).
|
13
|
-
1. _git_ (version >= 1.8.0). Do yourself a favor and use [Homebrew](http://brew.sh/) if you are on OSX.
|
14
|
-
1. _tmux_ (version >= 1.8.0). Do yourself a favor and use [Homebrew](http://brew.sh/) if you are on OSX.
|
11
|
+
1. _ruby_ (version >= 2.1.0). Do yourself a favor and use [RVM](https://rvm.io/rvm/install) to install Ruby.
|
12
|
+
1. _git_ (version >= 1.8.0). Do yourself a favor and use [Homebrew](http://brew.sh/) to install git, if you are on OSX.
|
13
|
+
1. _tmux_ (version >= 1.8.0). Do yourself a favor and use [Homebrew](http://brew.sh/) to install tmux, if you are on OSX.
|
15
14
|
1. _node.js_ (version >= 0.10.0). Yes, really, you need to install node becaue we use it to run the broker that handles all communications between all the pieces of the framework. Do yourself a favor and use [nvm](https://github.com/creationix/nvm).
|
15
|
+
1. _mongoDB_ (optional). You'll need mongoDB if you want to use it with `nutella.persist`.
|
16
16
|
|
17
|
-
Once you have all
|
17
|
+
Once you have all of these, to install nutella simply do:
|
18
18
|
```
|
19
19
|
gem install nutella_framework
|
20
20
|
```
|
@@ -23,19 +23,19 @@ Once the installation is complete you should be able to type `nutella` in your s
|
|
23
23
|
## nutella checkup
|
24
24
|
If you are reading this you probably already saw the warning: "Looks like this is a fresh installation of nutella. Please run 'nutella checkup' to check all dependencies are installed".
|
25
25
|
|
26
|
-
|
26
|
+
nutella is written in ruby but it's designed to run bots and interfaces written in virtually any programming language. All communications among these components are handled by an _MQTT broker_ which needs to be installed (together with its dependencies) before nutella can actually work correctly. Therefore **right after your install nutella** you should run:
|
27
27
|
```
|
28
28
|
nutella checkup
|
29
29
|
```
|
30
30
|
This will install the [Mosca](http://www.mosca.io/) MQTT broker and make sure all the dependencies required by nutella are installed as well.
|
31
31
|
|
32
|
-
Congratulations!
|
32
|
+
Congratulations! nutella is ready to use!
|
33
33
|
|
34
34
|
|
35
35
|
# Where next?
|
36
|
-
If you already have an application you want to tinker with (like [RoomQuake](https://github.com/ltg-uic/roomquake)) simply checkout the application to a local folder, `cd /to/my/local/folder` and start tinkering away. Not sure
|
36
|
+
If you already have an application you want to tinker with (like [RoomQuake](https://github.com/ltg-uic/roomquake)) simply checkout the application to a local folder, `cd /to/my/local/folder` and start tinkering away. Not sure how? Check out the [man page for the nutella command line tool](https://github.com/nutella-framework/nutella_framework/wiki).
|
37
37
|
|
38
|
-
If you want to create your own application,
|
38
|
+
If you want to create your own application, hold on tight, a tutorial is coming soon.
|
39
39
|
|
40
40
|
|
41
41
|
# Contributing
|
data/Rakefile
CHANGED
@@ -17,8 +17,8 @@ Jeweler::Tasks.new do |gem|
|
|
17
17
|
gem.name = "nutella_framework"
|
18
18
|
gem.homepage = "https://github.com/nutella-framework/nutella_framework"
|
19
19
|
gem.license = "MIT"
|
20
|
-
gem.summary = %Q{A framework
|
21
|
-
gem.description = %Q{
|
20
|
+
gem.summary = %Q{A rails-inspired framework for RoomApps}
|
21
|
+
gem.description = %Q{utella is a framework to create and run RoomApps}
|
22
22
|
gem.email = "tebemis@gmail.com"
|
23
23
|
gem.authors = ["Alessandro Gnoli"]
|
24
24
|
# dependencies defined in Gemfile
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.1
|
@@ -1,15 +1,51 @@
|
|
1
|
-
|
1
|
+
require_relative '../../nutella_lib/framework_core'
|
2
|
+
|
3
|
+
# Define a couple of utility functions to better deal with the runs list
|
4
|
+
def all_apps( runlist_file )
|
5
|
+
runlist_h = JSON.parse(IO.read(runlist_file))
|
6
|
+
runlist_h.keys
|
7
|
+
end
|
8
|
+
|
9
|
+
def runs_for_app( runlist_file, app_id )
|
10
|
+
runlist_h = JSON.parse(IO.read(runlist_file))
|
11
|
+
# If there is no app with this id, then return false and do nothing
|
12
|
+
return [] if runlist_h[app_id].nil?
|
13
|
+
runs = runlist_h[app_id]['runs']
|
14
|
+
runs.nil? ? [] : runs
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
# Parse configuration file and runlist from the command line
|
19
|
+
config_file = ARGV[0]
|
20
|
+
runlist_file = ARGV[1]
|
21
|
+
|
22
|
+
# Try to parse both config file and runlist and terminate if we can't
|
23
|
+
begin
|
24
|
+
config_h = JSON.parse(IO.read(config_file))
|
25
|
+
runlist_h = JSON.parse(IO.read(runlist_file))
|
26
|
+
rescue
|
27
|
+
# something went wrong
|
28
|
+
abort 'Impossible to parse configuration and/or runlist files!'
|
29
|
+
end
|
30
|
+
|
31
|
+
# Initialize this bot as framework component
|
32
|
+
nutella.f.init(config_h['broker'], 'app_runs_list_bot')
|
2
33
|
|
3
|
-
# This needs to be initialized as framework component like so:
|
4
|
-
# nutella.init_as_app_component('localhost', 'app_runs_list_bot')
|
5
|
-
nutella.init('localhost', 'my_app_id', 'no_run_id', 'app_runs_list_bot')
|
6
34
|
|
7
35
|
# Listen for runs_list requests (done by app components when they connect)
|
8
|
-
nutella.net.
|
9
|
-
|
10
|
-
['run_1', 'run_2', 'run_3'] # Return an array of names!
|
36
|
+
nutella.f.net.handle_requests_on_all_apps('app_runs_list', lambda do |req, app_id, from|
|
37
|
+
runs_for_app(runlist_file, app_id)
|
11
38
|
end)
|
12
39
|
|
13
|
-
# Whenever the list is updated, fire an update to the right app
|
14
40
|
|
15
|
-
|
41
|
+
# Whenever the runs list is updated, fire an updated runlist to all the apps
|
42
|
+
p = JSON.parse(IO.read(runlist_file))
|
43
|
+
while sleep .5
|
44
|
+
n = JSON.parse IO.read runlist_file
|
45
|
+
if p!=n
|
46
|
+
all_apps.each do |app_id, _|
|
47
|
+
nutella.f.net.publish_to_app(app_id, 'app_runs_list', runs_for_app(app_id, runlist_h))
|
48
|
+
end
|
49
|
+
p = n
|
50
|
+
end
|
51
|
+
end
|
data/lib/commands/start.rb
CHANGED
@@ -144,6 +144,7 @@ module Nutella
|
|
144
144
|
return false unless start_app_bots(app_id, app_path)
|
145
145
|
# Start all run-level bots
|
146
146
|
false unless start_run_bots( app_path, app_id, run_id, params )
|
147
|
+
true
|
147
148
|
end
|
148
149
|
|
149
150
|
|
@@ -238,6 +239,8 @@ module Nutella
|
|
238
239
|
command = "#{component_dir}/startup #{nutella_config_file} #{runs_list_file}"
|
239
240
|
pid = fork
|
240
241
|
exec(command) if pid.nil?
|
242
|
+
# Give it a second so they can start properly
|
243
|
+
sleep 1
|
241
244
|
# All went well so we return true
|
242
245
|
true
|
243
246
|
end
|
@@ -13,7 +13,13 @@ module Nutella
|
|
13
13
|
nutella_json_file = "#{cur_app_dir}/nutella.json"
|
14
14
|
# Check that there is a nutella.json file in the main directory of the application
|
15
15
|
if File.exist? nutella_json_file
|
16
|
-
|
16
|
+
begin
|
17
|
+
conf = JSON.parse( IO.read(nutella_json_file) )
|
18
|
+
rescue
|
19
|
+
console.warn 'The nutella.json file for this application does not contain properly formatted JSON'
|
20
|
+
return false
|
21
|
+
end
|
22
|
+
|
17
23
|
if conf['nutella_version'].nil?
|
18
24
|
return false
|
19
25
|
end
|
data/lib/config/runlist.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'config/persisted_hash'
|
2
|
+
require 'tmux/tmux'
|
2
3
|
|
3
4
|
module Nutella
|
4
5
|
|
@@ -21,9 +22,17 @@ module Nutella
|
|
21
22
|
end
|
22
23
|
|
23
24
|
|
24
|
-
# Returns all the
|
25
|
+
# Returns a list of all the apps in the runlist
|
25
26
|
#
|
26
|
-
# @return [Array<String>]
|
27
|
+
# @return [Array<String>] an array containing the app_ids of all the apps in the runlist
|
28
|
+
def all_apps
|
29
|
+
@ph.to_h.keys
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# Returns all the +run_id+s for ALL applications (i.e. the runslist)
|
34
|
+
#
|
35
|
+
# @return [Hash] the run list with all app_ids and run_ids
|
27
36
|
def all_runs
|
28
37
|
@ph.to_h
|
29
38
|
end
|
@@ -31,7 +40,7 @@ module Nutella
|
|
31
40
|
|
32
41
|
# Returns all the +run_id+s for a certain application
|
33
42
|
#
|
34
|
-
# @param [String] app_id
|
43
|
+
# @param [String] app_id of the application we want to find run_ids for
|
35
44
|
# @return [Array<String>] list of +run_id+s associated to the specified app_id
|
36
45
|
def runs_for_app( app_id )
|
37
46
|
# If there is no app, then return false and do nothing
|
data/nutella_framework.gemspec
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: nutella_framework 0.4.
|
5
|
+
# stub: nutella_framework 0.4.1 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "nutella_framework"
|
9
|
-
s.version = "0.4.
|
9
|
+
s.version = "0.4.1"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Alessandro Gnoli"]
|
14
|
-
s.date = "2015-03-
|
15
|
-
s.description = "
|
14
|
+
s.date = "2015-03-16"
|
15
|
+
s.description = "utella is a framework to create and run RoomApps"
|
16
16
|
s.email = "tebemis@gmail.com"
|
17
17
|
s.executables = ["nutella"]
|
18
18
|
s.extra_rdoc_files = [
|
@@ -39,6 +39,7 @@ Gem::Specification.new do |s|
|
|
39
39
|
"framework_components/main_interface/views/not_found_404.erb",
|
40
40
|
"framework_components/order.json.example",
|
41
41
|
"framework_components/runs_list_bot/app_runs_list_bot.rb",
|
42
|
+
"framework_components/runs_list_bot/startup",
|
42
43
|
"lib/commands/broker.rb",
|
43
44
|
"lib/commands/checkup.rb",
|
44
45
|
"lib/commands/compile.rb",
|
@@ -63,9 +64,10 @@ Gem::Specification.new do |s|
|
|
63
64
|
"lib/logging/nutella_logger.rb",
|
64
65
|
"lib/logging/nutella_logging.rb",
|
65
66
|
"lib/nutella_framework.rb",
|
66
|
-
"lib/nutella_lib_framework/api.rb",
|
67
67
|
"lib/tmux/tmux.rb",
|
68
68
|
"nutella_framework.gemspec",
|
69
|
+
"nutella_lib/framework_core.rb",
|
70
|
+
"nutella_lib/framework_net.rb",
|
69
71
|
"test/commands/test_cmd_cli_params_parsing.rb",
|
70
72
|
"test/commands/test_command_template.rb",
|
71
73
|
"test/config/test_current_app_utils.rb",
|
@@ -78,13 +80,12 @@ Gem::Specification.new do |s|
|
|
78
80
|
s.homepage = "https://github.com/nutella-framework/nutella_framework"
|
79
81
|
s.licenses = ["MIT"]
|
80
82
|
s.rubygems_version = "2.4.3"
|
81
|
-
s.summary = "A framework
|
83
|
+
s.summary = "A rails-inspired framework for RoomApps"
|
82
84
|
|
83
85
|
if s.respond_to? :specification_version then
|
84
86
|
s.specification_version = 4
|
85
87
|
|
86
88
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
87
|
-
s.add_runtime_dependency(%q<ansi>, [">= 1.4.3", "~> 1.4"])
|
88
89
|
s.add_runtime_dependency(%q<semantic>, [">= 1.3", "~> 1.3"])
|
89
90
|
s.add_runtime_dependency(%q<logging>, [">= 1.8.2", "~> 1.8"])
|
90
91
|
s.add_runtime_dependency(%q<git>, [">= 1.2.8", "~> 1.2"])
|
@@ -92,7 +93,7 @@ Gem::Specification.new do |s|
|
|
92
93
|
s.add_runtime_dependency(%q<thin>, [">= 1.6.3", "~> 1.6.3"])
|
93
94
|
s.add_runtime_dependency(%q<nokogiri>, [">= 1.6.3", "~> 1.6.3"])
|
94
95
|
s.add_runtime_dependency(%q<slop>, [">= 4.0.0", "~> 4.0.0"])
|
95
|
-
s.add_runtime_dependency(%q<nutella_lib>, [">= 0.4.
|
96
|
+
s.add_runtime_dependency(%q<nutella_lib>, [">= 0.4.1", "~> 0.4.1"])
|
96
97
|
s.add_development_dependency(%q<shoulda>, [">= 3", "~> 3"])
|
97
98
|
s.add_development_dependency(%q<yard>, [">= 0.8.7", "~> 0.8"])
|
98
99
|
s.add_development_dependency(%q<rdoc>, [">= 4.0", "~> 4.0"])
|
@@ -100,7 +101,6 @@ Gem::Specification.new do |s|
|
|
100
101
|
s.add_development_dependency(%q<jeweler>, [">= 2.0.1", "~> 2.0.1"])
|
101
102
|
s.add_development_dependency(%q<simplecov>, [">= 0", "~> 0"])
|
102
103
|
else
|
103
|
-
s.add_dependency(%q<ansi>, [">= 1.4.3", "~> 1.4"])
|
104
104
|
s.add_dependency(%q<semantic>, [">= 1.3", "~> 1.3"])
|
105
105
|
s.add_dependency(%q<logging>, [">= 1.8.2", "~> 1.8"])
|
106
106
|
s.add_dependency(%q<git>, [">= 1.2.8", "~> 1.2"])
|
@@ -108,7 +108,7 @@ Gem::Specification.new do |s|
|
|
108
108
|
s.add_dependency(%q<thin>, [">= 1.6.3", "~> 1.6.3"])
|
109
109
|
s.add_dependency(%q<nokogiri>, [">= 1.6.3", "~> 1.6.3"])
|
110
110
|
s.add_dependency(%q<slop>, [">= 4.0.0", "~> 4.0.0"])
|
111
|
-
s.add_dependency(%q<nutella_lib>, [">= 0.4.
|
111
|
+
s.add_dependency(%q<nutella_lib>, [">= 0.4.1", "~> 0.4.1"])
|
112
112
|
s.add_dependency(%q<shoulda>, [">= 3", "~> 3"])
|
113
113
|
s.add_dependency(%q<yard>, [">= 0.8.7", "~> 0.8"])
|
114
114
|
s.add_dependency(%q<rdoc>, [">= 4.0", "~> 4.0"])
|
@@ -117,7 +117,6 @@ Gem::Specification.new do |s|
|
|
117
117
|
s.add_dependency(%q<simplecov>, [">= 0", "~> 0"])
|
118
118
|
end
|
119
119
|
else
|
120
|
-
s.add_dependency(%q<ansi>, [">= 1.4.3", "~> 1.4"])
|
121
120
|
s.add_dependency(%q<semantic>, [">= 1.3", "~> 1.3"])
|
122
121
|
s.add_dependency(%q<logging>, [">= 1.8.2", "~> 1.8"])
|
123
122
|
s.add_dependency(%q<git>, [">= 1.2.8", "~> 1.2"])
|
@@ -125,7 +124,7 @@ Gem::Specification.new do |s|
|
|
125
124
|
s.add_dependency(%q<thin>, [">= 1.6.3", "~> 1.6.3"])
|
126
125
|
s.add_dependency(%q<nokogiri>, [">= 1.6.3", "~> 1.6.3"])
|
127
126
|
s.add_dependency(%q<slop>, [">= 4.0.0", "~> 4.0.0"])
|
128
|
-
s.add_dependency(%q<nutella_lib>, [">= 0.4.
|
127
|
+
s.add_dependency(%q<nutella_lib>, [">= 0.4.1", "~> 0.4.1"])
|
129
128
|
s.add_dependency(%q<shoulda>, [">= 3", "~> 3"])
|
130
129
|
s.add_dependency(%q<yard>, [">= 0.8.7", "~> 0.8"])
|
131
130
|
s.add_dependency(%q<rdoc>, [">= 4.0", "~> 4.0"])
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'nutella_lib'
|
2
|
+
require 'config/runlist'
|
3
|
+
|
4
|
+
# APIs sub-modules
|
5
|
+
require_relative 'framework_net'
|
6
|
+
|
7
|
+
|
8
|
+
module Nutella
|
9
|
+
|
10
|
+
# Accessor to the framework APIs sub-module
|
11
|
+
def Nutella.f
|
12
|
+
Nutella::Framework
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
# Framework-level APIs sub-module
|
18
|
+
module Framework
|
19
|
+
|
20
|
+
# Initializes this component as a framework component
|
21
|
+
# @param [String] broker_hostname
|
22
|
+
# @param [String] component_id
|
23
|
+
def self.init( broker_hostname, component_id )
|
24
|
+
Nutella.app_id = nil
|
25
|
+
Nutella.run_id = nil
|
26
|
+
Nutella.component_id = component_id
|
27
|
+
Nutella.resource_id = nil
|
28
|
+
Nutella.mqtt = SimpleMQTTClient.new broker_hostname
|
29
|
+
end
|
30
|
+
|
31
|
+
# Accessors for sub-modules
|
32
|
+
def self.net; Nutella::Framework::Net; end
|
33
|
+
def self.log; Nutella::Framework::Log; end
|
34
|
+
|
35
|
+
|
36
|
+
# Utility functions
|
37
|
+
|
38
|
+
|
39
|
+
# Parse command line arguments for framework level components
|
40
|
+
#
|
41
|
+
# @param [Array] args command line arguments array
|
42
|
+
# @return [String] broker
|
43
|
+
def self.parse_args(args)
|
44
|
+
if args.length < 1
|
45
|
+
STDERR.puts 'Couldn\'t read broker address from the command line, impossible to initialize component!'
|
46
|
+
return
|
47
|
+
end
|
48
|
+
return args[0]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Extracts the component name from the folder where the code for this component is located
|
52
|
+
#
|
53
|
+
# @return [String] the component name
|
54
|
+
def self.extract_component_id
|
55
|
+
Nutella.extract_component_id
|
56
|
+
end
|
57
|
+
|
58
|
+
# Sets the resource id
|
59
|
+
#
|
60
|
+
# @param [String] resource_id the resource id (i.e. the particular instance of this component)
|
61
|
+
def self.set_resource_id( resource_id )
|
62
|
+
Nutella.set_resource_id resource_id
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -1,43 +1,8 @@
|
|
1
|
-
require 'nutella_lib'
|
2
|
-
require 'config/runlist'
|
3
|
-
|
4
1
|
module Nutella
|
5
2
|
|
3
|
+
module Framework
|
6
4
|
|
7
|
-
|
8
|
-
# @param [String] broker_hostname
|
9
|
-
# @param [String] component_id
|
10
|
-
def self.init_as_f_component( broker_hostname, component_id )
|
11
|
-
@app_id = nil
|
12
|
-
@run_id = nil
|
13
|
-
@component_id = component_id
|
14
|
-
@resource_id = nil
|
15
|
-
@mqtt = SimpleMQTTClient.new broker_hostname
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
# Parse command line arguments for framework level components
|
20
|
-
#
|
21
|
-
# @param [Array] args command line arguments array
|
22
|
-
# @return [String] broker
|
23
|
-
def self.parse_f_component_args(args)
|
24
|
-
if args.length < 1
|
25
|
-
STDERR.puts 'Couldn\'t read broker address from the command line, impossible to initialize component!'
|
26
|
-
return
|
27
|
-
end
|
28
|
-
return args[0]
|
29
|
-
end
|
30
|
-
|
31
|
-
|
32
|
-
module Net
|
33
|
-
|
34
|
-
# Provides access to the net.app sub-module
|
35
|
-
def Net.f; Nutella::Net::Framework end
|
36
|
-
|
37
|
-
|
38
|
-
# This module implements the pub/sub and request/response APIs at the framework-level
|
39
|
-
module Framework
|
40
|
-
|
5
|
+
module Net
|
41
6
|
|
42
7
|
# @!group Framework-level communication APIs
|
43
8
|
|
@@ -287,7 +252,7 @@ module Nutella
|
|
287
252
|
# Only handle requests that have proper id set
|
288
253
|
return if type!='request' || id.nil?
|
289
254
|
# Execute callback and send response
|
290
|
-
m = Net.prepare_message_for_response( callback.call( payload, app_id, run_id, from), id )
|
255
|
+
m = Nutella::Net.prepare_message_for_response( callback.call( payload, app_id, run_id, from), id )
|
291
256
|
Nutella.mqtt.publish( mqtt_channel, m )
|
292
257
|
rescue JSON::ParserError
|
293
258
|
# Make sure that request contains JSON, if not drop the message
|
@@ -307,7 +272,83 @@ module Nutella
|
|
307
272
|
|
308
273
|
# @!group Framework-level APIs to communicate at the application-level
|
309
274
|
|
310
|
-
|
275
|
+
|
276
|
+
# Allows framework-level APIs to subscribe to an app-level channel within a specific run
|
277
|
+
#
|
278
|
+
# @param [String] app_id the specific application we are subscribing to
|
279
|
+
# @param [String] channel the run-level channel we are subscribing to. Can be wildcard.
|
280
|
+
# @param [Proc] callback the callback that is fired whenever a message is received on the channel.
|
281
|
+
# The passed callback takes the following parameters:
|
282
|
+
# - [String] message: the received message. Messages that are not JSON are discarded.
|
283
|
+
# - [String] channel: the framework-level channel the message was received on (optional, only for wildcard subscriptions)
|
284
|
+
# - [Hash] from: the sender's identifiers (run_id, app_id, component_id and optionally resource_id)
|
285
|
+
def self.subscribe_to_app(app_id, channel, callback)
|
286
|
+
Nutella::Net.subscribe_to(channel, callback, app_id, nil)
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
# Allows framework-level APIs to unsubscribe from an app-level channel within a specific run
|
291
|
+
#
|
292
|
+
# @param [String] app_id the specific application we are un-subscribing from
|
293
|
+
# @param [String] run_id the specific run we are un-subscribing from
|
294
|
+
# @param [String] channel the run-level channel we want to unsubscribe from. Can contain wildcard(s).
|
295
|
+
def self.unsubscribe_to_app( app_id, channel )
|
296
|
+
Nutella::Net.unsubscribe_to(channel, app_id, nil)
|
297
|
+
end
|
298
|
+
|
299
|
+
|
300
|
+
# Allows framework-level APIs to publish to an app-level channel within a specific run
|
301
|
+
#
|
302
|
+
# @param [String] app_id the specific application we are publishing to
|
303
|
+
# @param [String] channel the run-level channel we want to publish the message to. *CANNOT* contain wildcard(s)!
|
304
|
+
# @param [String] message the message we are publishing. This can be,
|
305
|
+
# nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
|
306
|
+
def self.publish_to_app(app_id, channel, message)
|
307
|
+
Nutella::Net.publish_to(channel, message, app_id, nil)
|
308
|
+
end
|
309
|
+
|
310
|
+
|
311
|
+
# Allows framework-level APIs to make a synchronous request to a run-level channel within a specific run
|
312
|
+
#
|
313
|
+
# @param [String] app_id the specific application we are making the request to
|
314
|
+
# @param [String] run_id the specific run we are making the request to
|
315
|
+
# @param [String] channel the channel we want to make the request to. *CANNOT* contain wildcard(s)!
|
316
|
+
# @param [Object] request the body of request. This can be,
|
317
|
+
# nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
|
318
|
+
def self.sync_request_to_app( app_id, channel, request)
|
319
|
+
Nutella::Net.sync_request_to(channel, request, app_id, nil)
|
320
|
+
end
|
321
|
+
|
322
|
+
|
323
|
+
# Allows framework-level APIs to make an asynchronous request to a run-level channel within a specific run
|
324
|
+
#
|
325
|
+
# @param [String] app_id the specific application we are making the request to
|
326
|
+
# @param [String] run_id the specific run we are making the request to
|
327
|
+
# @param [String] channel the channel we want to make the request to. *CANNOT* contain wildcard(s)!
|
328
|
+
# @param [Object] request the body of request. This can be,
|
329
|
+
# nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
|
330
|
+
# @param [Proc] callback the callback that is fired whenever a response is received. It takes one parameter (response).
|
331
|
+
def self.async_request_to_app( app_id, channel, request, callback)
|
332
|
+
Nutella::Net.async_request_to(channel, request, callback, app_id, nil)
|
333
|
+
end
|
334
|
+
|
335
|
+
|
336
|
+
# Allows framework-level APIs to handle requests on a run-level channel within a specific run
|
337
|
+
#
|
338
|
+
# @param [String] app_id the specific application requests are coming from
|
339
|
+
# @param [String] run_id the specific run requests are coming from
|
340
|
+
# @param [String] channel we want to listen for requests on. Can contain wildcard(s).
|
341
|
+
# @param [Proc] callback a lambda expression that is fired whenever a message is received.
|
342
|
+
# The passed callback takes the following parameters:
|
343
|
+
# - [String] the received message (payload). Messages that are not JSON are discarded.
|
344
|
+
# - [Hash] the sender's identifiers (run_id, app_id, component_id and optionally resource_id)
|
345
|
+
# - [*returns* Hash] The response sent back to the client that performed the request. Whatever is returned by the callback is marshaled into a JSON string and sent via MQTT.
|
346
|
+
def self.handle_requests_on_app(app_id, channel, callback)
|
347
|
+
Nutella::Net.handle_requests_on(channel, callback, app_id, nil)
|
348
|
+
end
|
349
|
+
|
350
|
+
|
351
|
+
|
311
352
|
|
312
353
|
# @!endgroup
|
313
354
|
|
@@ -315,10 +356,125 @@ module Nutella
|
|
315
356
|
|
316
357
|
# @!group Framework-level APIs to communicate at the application-level (broadcast)
|
317
358
|
|
318
|
-
|
359
|
+
|
360
|
+
# Allows framework-level APIs to subscribe to an app-level channel *for ALL apps*
|
361
|
+
#
|
362
|
+
# @param [String] channel the app-level channel we are subscribing to. Can be wildcard.
|
363
|
+
# @param [Proc] callback the callback that is fired whenever a message is received on the channel.
|
364
|
+
# The passed callback takes the following parameters:
|
365
|
+
# - [String] message: the received message. Messages that are not JSON are discarded.
|
366
|
+
# - [String] app_id: the app_id of the channel the message was sent on
|
367
|
+
# - [Hash] from: the sender's identifiers (run_id, app_id, component_id and optionally resource_id)
|
368
|
+
def self.subscribe_to_all_apps(channel, callback)
|
369
|
+
# Check the passed callback has the right number of arguments
|
370
|
+
raise 'You need to pass a callback with 3 parameters (payload, app_id, from) when subscribing to all apps!' if callback.parameters.length!=3
|
371
|
+
# Pad channel
|
372
|
+
padded_channel = Nutella::Net.pad_channel(channel, '+', nil)
|
373
|
+
mqtt_cb = lambda do |mqtt_message, mqtt_channel|
|
374
|
+
begin
|
375
|
+
type, from, payload, _ = Nutella::Net.extract_fields_from_message mqtt_message
|
376
|
+
app_id = self.extract_app_id mqtt_channel
|
377
|
+
callback.call(payload, app_id, from) if type=='publish'
|
378
|
+
rescue JSON::ParserError
|
379
|
+
# Make sure the message is JSON, if not drop the message
|
380
|
+
return
|
381
|
+
rescue
|
382
|
+
# Check the passed callback has the right number of arguments
|
383
|
+
STDERR.puts "The callback you passed to subscribe has the #{$!}: it needs 'payload', 'app_id' and 'from'"
|
384
|
+
end
|
385
|
+
end
|
386
|
+
# Add to subscriptions, save mqtt callback and subscribe
|
387
|
+
Nutella::Net.subscriptions.push padded_channel
|
388
|
+
Nutella::Net.callbacks.push mqtt_cb
|
389
|
+
Nutella.mqtt.subscribe( padded_channel, mqtt_cb )
|
390
|
+
end
|
391
|
+
|
392
|
+
|
393
|
+
# Allows framework-level APIs to unsubscribe from an app-level channel *for ALL apps*
|
394
|
+
#
|
395
|
+
# @param [String] channel the run-level channel we want to unsubscribe from. Can contain wildcard(s).
|
396
|
+
def self.unsubscribe_from_all_apps( channel )
|
397
|
+
Nutella::Net.unsubscribe_to(channel, '+', nil)
|
398
|
+
end
|
399
|
+
|
400
|
+
|
401
|
+
# Allows framework-level APIs to publish a message to an app-level channel *for ALL apps*
|
402
|
+
#
|
403
|
+
# @param [String] channel the app-level channel we want to publish the message to. *CANNOT* contain wildcard(s)!
|
404
|
+
# @param [Object] message the message we are publishing. This can be,
|
405
|
+
# nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
|
406
|
+
def self.publish_to_all_apps(channel, message)
|
407
|
+
Nutella.runlist.all_runs.each do |app_id, _|
|
408
|
+
Nutella::Net.publish_to(channel, message, app_id, nil)
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
|
413
|
+
# Allows framework-level APIs to send a request to a run-level channel *for ALL runs*
|
414
|
+
#
|
415
|
+
# @param [String] channel the app-level channel we want to make the request to. *CANNOT* contain wildcard(s)!
|
416
|
+
# @param [Object] request the body of request. This can be,
|
417
|
+
# nil/empty (default), a string, a hash and, in general, anything with a .to_json method.
|
418
|
+
# @param [Proc] callback the callback that is fired whenever a response is received. It takes one parameter (response).
|
419
|
+
def self.async_request_to_all_apps(channel, request, callback)
|
420
|
+
Nutella.runlist.all_runs.each do |app_id, _|
|
421
|
+
Nutella::Net.async_request_to(channel, request, callback, app_id, nil)
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
|
426
|
+
# Allows framework-level APIs to handle requests to a run-level channel *for ALL runs*
|
427
|
+
#
|
428
|
+
# @param [String] channel tha app-level channel we want to listen for requests on. Can contain wildcard(s).
|
429
|
+
# @param [Proc] callback a lambda expression that is fired whenever a message is received.
|
430
|
+
# The passed callback takes the following parameters:
|
431
|
+
# - [String] the received message (request). Messages that are not JSON are discarded.
|
432
|
+
# - [String] app_id: the app_id of the channel the request was sent on
|
433
|
+
# - [Hash] the sender's identifiers (from containing, run_id, app_id, component_id and optionally resource_id)
|
434
|
+
# - [*returns* Hash] The response sent back to the client that performed the request. Whatever is returned by the callback is marshaled into a JSON string and sent via MQTT.
|
435
|
+
def self.handle_requests_on_all_apps(channel, callback)
|
436
|
+
# Check the passed callback has the right number of arguments
|
437
|
+
raise 'You need to pass a callback with 3 parameters (request, run_id, from) when handling requests!' if callback.parameters.length!=3
|
438
|
+
# Pad channel
|
439
|
+
padded_channel = Nutella::Net.pad_channel(channel, '+', nil)
|
440
|
+
mqtt_cb = lambda do |request, mqtt_channel|
|
441
|
+
begin
|
442
|
+
# Extract nutella fields
|
443
|
+
type, from, payload, id = Nutella::Net.extract_fields_from_message request
|
444
|
+
app_id = self.extract_app_id mqtt_channel
|
445
|
+
# Only handle requests that have proper id set
|
446
|
+
return if type!='request' || id.nil?
|
447
|
+
# Execute callback and send response
|
448
|
+
m = Nutella::Net.prepare_message_for_response( callback.call( payload, app_id, from), id )
|
449
|
+
Nutella.mqtt.publish( mqtt_channel, m )
|
450
|
+
rescue JSON::ParserError
|
451
|
+
# Make sure that request contains JSON, if not drop the message
|
452
|
+
return
|
453
|
+
rescue
|
454
|
+
# Check the passed callback has the right number of arguments
|
455
|
+
STDERR.puts "The callback you passed to subscribe has the #{$!}: it needs 'request', 'app_id' and 'from'"
|
456
|
+
end
|
457
|
+
end
|
458
|
+
# Subscribe to the channel
|
459
|
+
Nutella.mqtt.subscribe( padded_channel, mqtt_cb )
|
460
|
+
end
|
319
461
|
|
320
462
|
# @!endgroup
|
321
463
|
|
464
|
+
# ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
465
|
+
|
466
|
+
# Listens for incoming messages. All this function
|
467
|
+
# does is to put the thread to sleep and wait for something to
|
468
|
+
# happen over the network to wake up.
|
469
|
+
def self.listen
|
470
|
+
begin
|
471
|
+
sleep
|
472
|
+
rescue Interrupt
|
473
|
+
# Simply returns once interrupted
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
|
322
478
|
private
|
323
479
|
|
324
480
|
def self.extract_run_id_and_app_id( mqtt_channel )
|
@@ -327,7 +483,13 @@ module Nutella
|
|
327
483
|
end
|
328
484
|
|
329
485
|
|
330
|
-
|
486
|
+
def self.extract_app_id( mqtt_channel )
|
487
|
+
sp = mqtt_channel.sub('/nutella/apps/', '').split('/')
|
488
|
+
return sp[0]
|
489
|
+
end
|
490
|
+
|
491
|
+
end # net
|
492
|
+
|
493
|
+
end # framework
|
331
494
|
|
332
|
-
|
333
|
-
end
|
495
|
+
end # nutella
|
metadata
CHANGED
@@ -1,35 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nutella_framework
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alessandro Gnoli
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: ansi
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 1.4.3
|
20
|
-
- - "~>"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '1.4'
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 1.4.3
|
30
|
-
- - "~>"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '1.4'
|
33
13
|
- !ruby/object:Gem::Dependency
|
34
14
|
name: semantic
|
35
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -176,20 +156,20 @@ dependencies:
|
|
176
156
|
requirements:
|
177
157
|
- - ">="
|
178
158
|
- !ruby/object:Gem::Version
|
179
|
-
version: 0.4.
|
159
|
+
version: 0.4.1
|
180
160
|
- - "~>"
|
181
161
|
- !ruby/object:Gem::Version
|
182
|
-
version: 0.4.
|
162
|
+
version: 0.4.1
|
183
163
|
type: :runtime
|
184
164
|
prerelease: false
|
185
165
|
version_requirements: !ruby/object:Gem::Requirement
|
186
166
|
requirements:
|
187
167
|
- - ">="
|
188
168
|
- !ruby/object:Gem::Version
|
189
|
-
version: 0.4.
|
169
|
+
version: 0.4.1
|
190
170
|
- - "~>"
|
191
171
|
- !ruby/object:Gem::Version
|
192
|
-
version: 0.4.
|
172
|
+
version: 0.4.1
|
193
173
|
- !ruby/object:Gem::Dependency
|
194
174
|
name: shoulda
|
195
175
|
requirement: !ruby/object:Gem::Requirement
|
@@ -310,7 +290,7 @@ dependencies:
|
|
310
290
|
- - "~>"
|
311
291
|
- !ruby/object:Gem::Version
|
312
292
|
version: '0'
|
313
|
-
description:
|
293
|
+
description: utella is a framework to create and run RoomApps
|
314
294
|
email: tebemis@gmail.com
|
315
295
|
executables:
|
316
296
|
- nutella
|
@@ -338,6 +318,7 @@ files:
|
|
338
318
|
- framework_components/main_interface/views/not_found_404.erb
|
339
319
|
- framework_components/order.json.example
|
340
320
|
- framework_components/runs_list_bot/app_runs_list_bot.rb
|
321
|
+
- framework_components/runs_list_bot/startup
|
341
322
|
- lib/commands/broker.rb
|
342
323
|
- lib/commands/checkup.rb
|
343
324
|
- lib/commands/compile.rb
|
@@ -362,9 +343,10 @@ files:
|
|
362
343
|
- lib/logging/nutella_logger.rb
|
363
344
|
- lib/logging/nutella_logging.rb
|
364
345
|
- lib/nutella_framework.rb
|
365
|
-
- lib/nutella_lib_framework/api.rb
|
366
346
|
- lib/tmux/tmux.rb
|
367
347
|
- nutella_framework.gemspec
|
348
|
+
- nutella_lib/framework_core.rb
|
349
|
+
- nutella_lib/framework_net.rb
|
368
350
|
- test/commands/test_cmd_cli_params_parsing.rb
|
369
351
|
- test/commands/test_command_template.rb
|
370
352
|
- test/config/test_current_app_utils.rb
|
@@ -396,5 +378,5 @@ rubyforge_project:
|
|
396
378
|
rubygems_version: 2.4.3
|
397
379
|
signing_key:
|
398
380
|
specification_version: 4
|
399
|
-
summary: A framework
|
381
|
+
summary: A rails-inspired framework for RoomApps
|
400
382
|
test_files: []
|