nutella_framework 0.4.0 → 0.4.1

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
  SHA1:
3
- metadata.gz: 98a1d74bc599d78623959deb2d80d7ef4b5527b0
4
- data.tar.gz: 229db1d35c9f3000f6510fa44e075878e21b7f07
3
+ metadata.gz: 0ee0147d7ad4b06c602ad742ad464804686a73af
4
+ data.tar.gz: 5255b9ac953ca5d4a2608943ed6d7fab61cebaaf
5
5
  SHA512:
6
- metadata.gz: 0673b2e12cd08dd77e2359b3aa05f7d0d9d6b36e415de55f0df13ef201887fd5c1e0303e695bef502cc2b877df6b72a4aa405d358375ff0498635a4178337322
7
- data.tar.gz: 274b0ea11c7671bb8cb42f1d1179026f5a6cfb04d3af52a60d91b3e3a8d97d804457b248203733b821cc2b75bd7ff390c2e1089822627a5525bbea7a8640ae74
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.0', '>=0.4.0'
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
  [![Build Status](https://travis-ci.org/nutella-framework/nutella_framework.svg?branch=master)](https://travis-ci.org/nutella-framework/nutella_framework)
4
4
  [![Code Climate](https://codeclimate.com/github/nutella-framework/nutella_framework/badges/gpa.svg)](https://codeclimate.com/github/nutella-framework/nutella_framework)
5
5
 
6
- # Nutella
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 lots of technologies that already exists. Therefore, before you can successfully install nutella, you need to install (if you don't have them already):
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 the pieces that you need, to install nutella simply do:
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
- Nutella is written in ruby but is designed to run bots and interfaces written in virtually any programming language. All communications among these components are routed through 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:
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! Nutella is ready to use!
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 what to do? Check out our [nutella Command Line Tool man page](https://github.com/nutella-framework/nutella_framework/wiki/Nutella-Command-Line-Interface).
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, check out the [new app tutorial](https://github.com/nutella-framework/nutella_framework/wiki/New-application-tutorial).
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 to create and run classroom narratives}
21
- gem.description = %Q{Nutella is a framework to create and run classroom narratives}
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.0
1
+ 0.4.1
@@ -1,15 +1,51 @@
1
- require 'nutella_lib'
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.app.handle_requests('app_runs_list', lambda do |req, from|
9
- from['app_id'] # Use this info to fetch the appropriate runs
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
- nutella.net.listen
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
@@ -0,0 +1,8 @@
1
+ #!/bin/sh
2
+
3
+ BASEDIR=$(dirname $0)
4
+
5
+ # Pass the configuration file and the runlist
6
+
7
+ ruby $BASEDIR/app_runs_list_bot.rb $1 $2 > /dev/null 2>&1 &
8
+ echo $! > $BASEDIR/.pid
@@ -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
- conf = JSON.parse( IO.read(nutella_json_file) )
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
@@ -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 +run_id+s for ALL applications
25
+ # Returns a list of all the apps in the runlist
25
26
  #
26
- # @return [Array<String>] list of +run_id+s associated to the specified app_id
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 the id of the application we want to find run_ids for
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
@@ -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.0 ruby lib
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.0"
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-13"
15
- s.description = "Nutella is a framework to create and run classroom narratives"
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 to create and run classroom narratives"
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.0", "~> 0.4.0"])
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.0", "~> 0.4.0"])
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.0", "~> 0.4.0"])
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
- # Initializes this component as a framework component
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
- # TODO
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
- # TODO
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
- end
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
- end
333
- end
495
+ end # nutella
@@ -1,6 +1,6 @@
1
1
  require 'helper'
2
2
 
3
- require_relative '../../lib/nutella_lib_framework/api'
3
+ require_relative '../../nutella_lib/framework_core'
4
4
 
5
5
 
6
6
 
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.0
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-13 00:00:00.000000000 Z
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.0
159
+ version: 0.4.1
180
160
  - - "~>"
181
161
  - !ruby/object:Gem::Version
182
- version: 0.4.0
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.0
169
+ version: 0.4.1
190
170
  - - "~>"
191
171
  - !ruby/object:Gem::Version
192
- version: 0.4.0
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: Nutella is a framework to create and run classroom narratives
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 to create and run classroom narratives
381
+ summary: A rails-inspired framework for RoomApps
400
382
  test_files: []