benevolent_gaze 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +112 -0
- data/Rakefile +2 -0
- data/benevolent_gaze.gemspec +35 -0
- data/bin/benevolent_gaze +5 -0
- data/frontend/.gitignore +15 -0
- data/frontend/Gemfile +21 -0
- data/frontend/Gemfile.lock +162 -0
- data/frontend/config.rb +56 -0
- data/frontend/data/site.yml +4 -0
- data/frontend/source/images/.gitkeep +0 -0
- data/frontend/source/images/board@1x.png +0 -0
- data/frontend/source/images/city@1x.png +0 -0
- data/frontend/source/images/complete_left_panel@1x.png +0 -0
- data/frontend/source/images/icon_password@1x.png +0 -0
- data/frontend/source/images/icon_wifi@1x.png +0 -0
- data/frontend/source/images/logo@1x.png +0 -0
- data/frontend/source/images/pin_rope@1x.png +0 -0
- data/frontend/source/images/register@2x.png +0 -0
- data/frontend/source/images/sky@1x.png +0 -0
- data/frontend/source/images/sky_register@1x.png +0 -0
- data/frontend/source/images/sun@1x.png +0 -0
- data/frontend/source/images/tape_left@1x.png +0 -0
- data/frontend/source/images/tape_right@1x.png +0 -0
- data/frontend/source/images/thanks@2x.png +0 -0
- data/frontend/source/images/uploads/info.txt +1 -0
- data/frontend/source/images/visitor_art@1x.png +0 -0
- data/frontend/source/images/welcome@1x.png +0 -0
- data/frontend/source/index.html.haml +33 -0
- data/frontend/source/javascripts/all.js +161 -0
- data/frontend/source/layouts/layout.haml +23 -0
- data/frontend/source/register.html.haml +21 -0
- data/frontend/source/stylesheets/animate.css.scss +3176 -0
- data/frontend/source/stylesheets/application.css.scss +291 -0
- data/frontend/source/thanks.html.haml +8 -0
- data/kiosk/.env +7 -0
- data/kiosk/Procfile +2 -0
- data/kiosk/public/fonts/bootstrap/glyphicons-halflings-regular-22037a34.woff +0 -0
- data/kiosk/public/fonts/bootstrap/glyphicons-halflings-regular-66b1fc67.svg +229 -0
- data/kiosk/public/fonts/bootstrap/glyphicons-halflings-regular-aafafdc0.ttf +0 -0
- data/kiosk/public/fonts/bootstrap/glyphicons-halflings-regular-f3a9a3b6.eot +0 -0
- data/kiosk/public/images/board@1x-b5fb87e5.png +0 -0
- data/kiosk/public/images/city@1x-22396032.png +0 -0
- data/kiosk/public/images/complete_left_panel@1x-7dec25da.png +0 -0
- data/kiosk/public/images/icon_password@1x-fb34b974.png +0 -0
- data/kiosk/public/images/icon_wifi@1x-e92e9c20.png +0 -0
- data/kiosk/public/images/logo@1x-927932fa.png +0 -0
- data/kiosk/public/images/pin_rope@1x-f5912856.png +0 -0
- data/kiosk/public/images/register@2x-328082c6.png +0 -0
- data/kiosk/public/images/sky@1x-47babe39.png +0 -0
- data/kiosk/public/images/sky_register@1x-cd96f779.png +0 -0
- data/kiosk/public/images/sun@1x-4f644bff.png +0 -0
- data/kiosk/public/images/tape_left@1x-9f3af6c1.png +0 -0
- data/kiosk/public/images/tape_right@1x-646752c4.png +0 -0
- data/kiosk/public/images/thanks@2x-694b424f.png +0 -0
- data/kiosk/public/images/uploads/info.txt +1 -0
- data/kiosk/public/images/visitor_art@1x-21d82dcb.png +0 -0
- data/kiosk/public/images/welcome@1x-7d17fbb9.png +0 -0
- data/kiosk/public/index.html +74 -0
- data/kiosk/public/javascripts/all-eb365891.js +12256 -0
- data/kiosk/public/register.html +52 -0
- data/kiosk/public/stylesheets/animate-31203878.css +6 -0
- data/kiosk/public/stylesheets/application-70841e1d.css +1 -0
- data/kiosk/public/thanks.html +36 -0
- data/lib/benevolent_gaze/bgapp.rb +39 -0
- data/lib/benevolent_gaze/cli.rb +153 -0
- data/lib/benevolent_gaze/kiosk.rb +164 -0
- data/lib/benevolent_gaze/kiosk_bak.rb +164 -0
- data/lib/benevolent_gaze/tracker.rb +87 -0
- data/lib/benevolent_gaze/version.rb +3 -0
- data/lib/benevolent_gaze.rb +5 -0
- data/website/.gitignore +18 -0
- data/website/Gemfile +20 -0
- data/website/Gemfile.lock +151 -0
- data/website/config.rb +58 -0
- data/website/data/site.yml +4 -0
- data/website/source/CNAME +1 -0
- data/website/source/fonts/OpenSans-Regular-webfont.eot +0 -0
- data/website/source/fonts/OpenSans-Regular-webfont.svg +1831 -0
- data/website/source/fonts/OpenSans-Regular-webfont.ttf +0 -0
- data/website/source/fonts/OpenSans-Regular-webfont.woff +0 -0
- data/website/source/fonts/Oswald-Bold.eot +0 -0
- data/website/source/fonts/Oswald-Bold.svg +0 -0
- data/website/source/fonts/Oswald-Bold.ttf +0 -0
- data/website/source/fonts/Oswald-Bold.woff +0 -0
- data/website/source/fonts/Oswald-Light.eot +0 -0
- data/website/source/fonts/Oswald-Light.svg +0 -0
- data/website/source/fonts/Oswald-Light.ttf +0 -0
- data/website/source/fonts/Oswald-Light.woff +0 -0
- data/website/source/fonts/Oswald-Regular.eot +0 -0
- data/website/source/fonts/Oswald-Regular.svg +0 -0
- data/website/source/fonts/Oswald-Regular.ttf +0 -0
- data/website/source/fonts/Oswald-Regular.woff +0 -0
- data/website/source/fonts/TradeGothic-BoldCondTwenty.eot +0 -0
- data/website/source/fonts/TradeGothic-BoldCondTwenty.svg +0 -0
- data/website/source/fonts/TradeGothic-BoldCondTwenty.ttf +0 -0
- data/website/source/fonts/TradeGothic-BoldCondTwenty.woff +0 -0
- data/website/source/fonts/TradeGothic-CondEighteen.eot +0 -0
- data/website/source/fonts/TradeGothic-CondEighteen.svg +0 -0
- data/website/source/fonts/TradeGothic-CondEighteen.ttf +0 -0
- data/website/source/fonts/TradeGothic-CondEighteen.woff +0 -0
- data/website/source/fonts/telegrafico_by_ficod-webfont.eot +0 -0
- data/website/source/fonts/telegrafico_by_ficod-webfont.svg +95 -0
- data/website/source/fonts/telegrafico_by_ficod-webfont.ttf +0 -0
- data/website/source/fonts/telegrafico_by_ficod-webfont.woff +0 -0
- data/website/source/images/.gitkeep +0 -0
- data/website/source/images/gaze.png +0 -0
- data/website/source/images/splash/accessorized_badge@2x.png +0 -0
- data/website/source/images/splash/benevolent_gaze_icon@2x.png +0 -0
- data/website/source/images/splash/benevolent_gaze_logo@2x.png +0 -0
- data/website/source/images/splash/benevolent_gaze_logo_color@2x.png +0 -0
- data/website/source/images/splash/benevolent_gaze_text@2x.png +0 -0
- data/website/source/images/splash/brackets.png +0 -0
- data/website/source/images/splash/checkmark.png +0 -0
- data/website/source/images/splash/circle_for_logo@2x.png +0 -0
- data/website/source/images/splash/cloud_cover@2x.png +0 -0
- data/website/source/images/splash/clouds.png +0 -0
- data/website/source/images/splash/complete_badge@2x.png +0 -0
- data/website/source/images/splash/down_arrow.png +0 -0
- data/website/source/images/splash/easy_badge@2x.png +0 -0
- data/website/source/images/splash/faded-clouds.png +0 -0
- data/website/source/images/splash/github_banner@2x.png +0 -0
- data/website/source/images/splash/hero_bkg.png +0 -0
- data/website/source/images/splash/left-bracket.png +0 -0
- data/website/source/images/splash/more-awesome-stuff.png +0 -0
- data/website/source/images/splash/overbracket.png +0 -0
- data/website/source/images/splash/rainbow@2x.png +0 -0
- data/website/source/images/splash/rainbow_banner@2x.png +0 -0
- data/website/source/images/splash/right-bracket.png +0 -0
- data/website/source/images/splash/seed-logo-color.png +0 -0
- data/website/source/images/splash/seed-logo.png +0 -0
- data/website/source/images/splash/sensible-defaults.png +0 -0
- data/website/source/images/splash/single_check@2x.png +0 -0
- data/website/source/images/splash/sky_background.png +0 -0
- data/website/source/images/splash/solid-gems.png +0 -0
- data/website/source/images/splash/ted.png +0 -0
- data/website/source/images/splash/ted_on_unicorn@2x.png +0 -0
- data/website/source/images/splash/view-me-on-github.png +0 -0
- data/website/source/index.html.haml +181 -0
- data/website/source/javascripts/all.js +3 -0
- data/website/source/javascripts/modernizr.js +1406 -0
- data/website/source/javascripts/scrollReveal.js +398 -0
- data/website/source/layouts/_footer.html.haml +34 -0
- data/website/source/layouts/_javascripts.erb +9 -0
- data/website/source/layouts/docs_layout.haml +23 -0
- data/website/source/layouts/layout.haml +87 -0
- data/website/source/stylesheets/animate.css +3158 -0
- data/website/source/stylesheets/application.css.scss +534 -0
- data/website/source/stylesheets/fonts/socicon-webfont.eot +0 -0
- data/website/source/stylesheets/fonts/socicon-webfont.svg +90 -0
- data/website/source/stylesheets/fonts/socicon-webfont.ttf +0 -0
- data/website/source/stylesheets/fonts/socicon-webfont.woff +0 -0
- data/website/source/stylesheets/socicons.css +124 -0
- metadata +382 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'thor/actions'
|
3
|
+
require 'csv'
|
4
|
+
require 'benevolent_gaze/kiosk'
|
5
|
+
require 'benevolent_gaze/tracker'
|
6
|
+
|
7
|
+
include FileUtils
|
8
|
+
|
9
|
+
module BenevolentGaze
|
10
|
+
class Cli < Thor
|
11
|
+
include Thor::Actions
|
12
|
+
source_root File.expand_path("../../../kiosk", __FILE__)
|
13
|
+
|
14
|
+
desc "kiosk", "Start up the sinatra app that displays the users"
|
15
|
+
def kiosk
|
16
|
+
BenevolentGaze::Kiosk.run!
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "tracker", "Start up the tracking daemon that looks at the network"
|
20
|
+
def tracker
|
21
|
+
BenevolentGaze::Tracker.run!
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "add_user device name image", "Add single user's device name, name and image"
|
25
|
+
long_desc <<-LONGDESC
|
26
|
+
This command takes a user's device name, real name and image url and maps them
|
27
|
+
so that Benevolent Gaze can use the information when they log onto your network.
|
28
|
+
LONGDESC
|
29
|
+
|
30
|
+
def add_user(device_name, name, image_url)
|
31
|
+
`redis-cli set "name:#{device_name}" "#{name}"`
|
32
|
+
`redis-cli set "image:#{name}" "#{image_url}"`
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "assign_users", "This will prompt you for each current user without an associated name so that you can assign one."
|
36
|
+
def assign_users
|
37
|
+
# users = `redis-cli hgetall "current_devices"`.split("\n")
|
38
|
+
require 'redis'
|
39
|
+
redis = Redis.new
|
40
|
+
users = redis.hgetall "current_devices"
|
41
|
+
|
42
|
+
puts "Right now, these are the devices on your network"
|
43
|
+
users.each { |u,v| puts " #{u}" }
|
44
|
+
|
45
|
+
users.each do |u, val|
|
46
|
+
val = redis.get "name:#{u}"
|
47
|
+
if val.nil? || val.empty?
|
48
|
+
puts "Do you know whose device this is #{u}? ( y/n )"
|
49
|
+
response = $stdin.gets.chomp.strip
|
50
|
+
if response == "y"
|
51
|
+
puts "Please enter their name."
|
52
|
+
name_response = $stdin.gets.chomp.strip
|
53
|
+
redis.set "name:#{u}", "#{name_response}"
|
54
|
+
# `redis-cli set "name:#{u}" "#{name_response}"`
|
55
|
+
|
56
|
+
puts "Do you have an image for this user? ( y/n )"
|
57
|
+
image_response = $stdin.gets.chomp.strip
|
58
|
+
if image_response == "y"
|
59
|
+
puts "Please enter the image url."
|
60
|
+
image_url_response = $stdin.gets.chomp.strip
|
61
|
+
redis.set "image:#{name_response}", image_url_response
|
62
|
+
end
|
63
|
+
end
|
64
|
+
else
|
65
|
+
puts "#{Thor::Shell::Color::MAGENTA}#{u} looks like it has a name already associated with them.#{Thor::Shell::Color::CLEAR}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
self.bg_flair
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "dump_csv [FILENAME]", "This dumps the current_devices"
|
72
|
+
def dump_csv( filename )
|
73
|
+
require 'redis'
|
74
|
+
redis = Redis.new
|
75
|
+
users = redis.hgetall "current_devices"
|
76
|
+
CSV.open( filename, "wb" ) do |out|
|
77
|
+
users.each do |device, name|
|
78
|
+
name = redis.get "name:#{device}"
|
79
|
+
image = redis.get "image:#{name}"
|
80
|
+
out << [device,name,image]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
self.bg_flair
|
84
|
+
puts "#{filename} created"
|
85
|
+
end
|
86
|
+
|
87
|
+
desc "bulk_assign yourcsv.csv", "This takes a csv file as an argument formated in the following way. device_name, real_name, image_url"
|
88
|
+
def bulk_assign(csv_path)
|
89
|
+
CSV.foreach(csv_path) do |row|
|
90
|
+
puts "Loading device info for #{row[0]} -> #{row[1]}"
|
91
|
+
device_name = row[0]
|
92
|
+
real_name = row[1]
|
93
|
+
image_url = row[2]
|
94
|
+
|
95
|
+
unless real_name.nil? || real_name.empty?
|
96
|
+
`redis-cli set "name:#{device_name}" "#{real_name}"`
|
97
|
+
end
|
98
|
+
|
99
|
+
unless image_url.nil? || image_url.empty?
|
100
|
+
`redis-cli set "image:#{real_name}" "#{image_url}"`
|
101
|
+
end
|
102
|
+
end
|
103
|
+
# puts `redis-cli keys "*"`
|
104
|
+
puts "#{Thor::Shell::Color::MAGENTA}The CSV has now been added.#{Thor::Shell::Color::CLEAR}"
|
105
|
+
self.bg_flair
|
106
|
+
end
|
107
|
+
|
108
|
+
desc "install wifi_username, wifi_password", "This commands installs the necessary components in the gem and pulls the assets into a local folder so that you can save to your local file system if you do not want to use s3 and also enables you to customize your kiosk."
|
109
|
+
def install(uname, pass)
|
110
|
+
directory ".", "bg_public"
|
111
|
+
env_file = "bg_public/.env"
|
112
|
+
new_path = File.expand_path("./bg_public")
|
113
|
+
gsub_file(env_file, /.*PUBLIC_FOLDER.*/, "PUBLIC_FOLDER=\"#{new_path}/public\"")
|
114
|
+
gsub_file("bg_public/public/index.html", "happyfuncorp3", uname)
|
115
|
+
gsub_file("bg_public/public/index.html", "happiness4u", pass)
|
116
|
+
puts <<-CUSTOMIZE
|
117
|
+
|
118
|
+
#{Thor::Shell::Color::MAGENTA}**************************************************#{Thor::Shell::Color::CLEAR}
|
119
|
+
|
120
|
+
Generated the bg_public folder where you should go to customize images and to run
|
121
|
+
|
122
|
+
```foreman start```
|
123
|
+
|
124
|
+
Please modify the .env file with the relevant information mentioned in the README.
|
125
|
+
|
126
|
+
You can now customize your kiosk, by switching out the graphics in the images folder.
|
127
|
+
Please replace the images with the images of the same size.
|
128
|
+
|
129
|
+
Uploaded images will save to your local filesystem if you do not supply AWS creds.
|
130
|
+
|
131
|
+
#{Thor::Shell::Color::MAGENTA}**************************************************#{Thor::Shell::Color::CLEAR}
|
132
|
+
CUSTOMIZE
|
133
|
+
|
134
|
+
self.bg_flair
|
135
|
+
end
|
136
|
+
|
137
|
+
desc "bg_flair prints Benevolent Gaze in ascii art letters, because awesome.", "This command prints Benevolent Gaze in ascii art letters, because...um...well...it's cool looking!"
|
138
|
+
def bg_flair
|
139
|
+
@bg = <<-BG
|
140
|
+
#{Thor::Shell::Color::CYAN}
|
141
|
+
____ _ _ _____
|
142
|
+
| _ \\ | | | | / ____|
|
143
|
+
| |_) | ___ _ __ _____ _____ | | ___ _ __ | |_ | | __ __ _ _______
|
144
|
+
| _ < / _ \\ '_ \\ / _ \\ \\ / / _ \\| |/ _ \\ '_ \\| __| | | |_ |/ _` |_ / _ \\
|
145
|
+
| |_) | __/ | | | __/\\ V / (_) | | __/ | | | |_ | |__| | (_| |/ / __/
|
146
|
+
|____/ \\___|_| |_|\\___| \\_/ \\___/|_|\\___|_| |_|\\__| \\_____|\\__,_/___\\___|
|
147
|
+
|
148
|
+
#{Thor::Shell::Color::CLEAR}
|
149
|
+
BG
|
150
|
+
puts @bg
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'sinatra/support'
|
4
|
+
require 'sinatra/json'
|
5
|
+
require 'redis'
|
6
|
+
require 'resolv'
|
7
|
+
require 'sinatra/cross_origin'
|
8
|
+
require 'aws/s3'
|
9
|
+
require 'SecureRandom'
|
10
|
+
require 'mini_magick'
|
11
|
+
|
12
|
+
Encoding.default_external = 'utf-8' if defined?(::Encoding)
|
13
|
+
|
14
|
+
module BenevolentGaze
|
15
|
+
class Kiosk < Sinatra::Base
|
16
|
+
set server: 'thin', connections: []
|
17
|
+
set :bind, '0.0.0.0'
|
18
|
+
set :app_file, __FILE__
|
19
|
+
set :port, ENV['IPORT']
|
20
|
+
set :static, true
|
21
|
+
set :public_folder, ENV['PUBLIC_FOLDER'] || "public"
|
22
|
+
@@local_file_system = ENV['PUBLIC_FOLDER']
|
23
|
+
|
24
|
+
register Sinatra::CrossOrigin
|
25
|
+
|
26
|
+
configure do
|
27
|
+
unless ENV['AWS_ACCESS_KEY_ID'].nil? || ENV['AWS_ACCESS_KEY_ID'].empty? || ENV['AWS_SECRET_ACCESS_KEY'].empty? || ENV['AWS_CDN_BUCKET'].empty?
|
28
|
+
USE_AWS = true
|
29
|
+
else
|
30
|
+
USE_AWS = false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
helpers do
|
35
|
+
def upload(filename, file, device_name)
|
36
|
+
doomsday = Time.mktime(2038, 1, 18).to_i
|
37
|
+
if (filename)
|
38
|
+
new_file_name = device_name.to_s + SecureRandom.uuid.to_s + filename
|
39
|
+
bucket = ENV['AWS_CDN_BUCKET']
|
40
|
+
image = MiniMagick::Image.open(file.path)
|
41
|
+
|
42
|
+
animated_gif = `identify -format "%n" "#{file.path}"`.to_i > 1
|
43
|
+
if animated_gif
|
44
|
+
image.repage "0x0"
|
45
|
+
if image.height > image.width
|
46
|
+
image.resize "300"
|
47
|
+
offset = (image.height/2) - 150
|
48
|
+
image.crop("300x300+0+#{offset}")
|
49
|
+
else
|
50
|
+
image.resize "x300"
|
51
|
+
offset = (image.width/2) - 150
|
52
|
+
image.crop("300x300+#{offset}+0")
|
53
|
+
end
|
54
|
+
image << "+repage"
|
55
|
+
else
|
56
|
+
image.auto_orient
|
57
|
+
if image.height > image.width
|
58
|
+
image.resize "300"
|
59
|
+
offset = (image.height/2) - 150
|
60
|
+
image.crop("300x300+0+#{offset}")
|
61
|
+
else
|
62
|
+
image.resize "x300"
|
63
|
+
offset = (image.width/2) - 150
|
64
|
+
image.crop("300x300+#{offset}+0")
|
65
|
+
end
|
66
|
+
image.format "png"
|
67
|
+
end
|
68
|
+
|
69
|
+
if USE_AWS
|
70
|
+
AWS::S3::Base.establish_connection!(
|
71
|
+
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
|
72
|
+
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
|
73
|
+
)
|
74
|
+
AWS::S3::S3Object.store(
|
75
|
+
new_file_name,
|
76
|
+
image.to_blob,
|
77
|
+
bucket,
|
78
|
+
:access => :public_read
|
79
|
+
)
|
80
|
+
image_url = AWS::S3::S3Object.url_for( new_file_name, bucket, :expires => doomsday )
|
81
|
+
else
|
82
|
+
upload_path = @@local_file_system + '/images/uploads/'
|
83
|
+
file_on_disk = upload_path + new_file_name
|
84
|
+
File.open(File.expand_path(file_on_disk), "w") do |f|
|
85
|
+
f.write(image.to_blob)
|
86
|
+
end
|
87
|
+
image_url = "images/uploads/" + new_file_name
|
88
|
+
end
|
89
|
+
|
90
|
+
return image_url
|
91
|
+
|
92
|
+
else
|
93
|
+
return nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
get "/" do
|
99
|
+
redirect "index.html"
|
100
|
+
end
|
101
|
+
|
102
|
+
post "/register" do
|
103
|
+
dns = Resolv.new
|
104
|
+
device_name = dns.getname(request.ip)
|
105
|
+
r = Redis.new
|
106
|
+
|
107
|
+
compound_name = nil
|
108
|
+
|
109
|
+
if !params[:real_first_name].empty? || !params[:real_last_name].empty?
|
110
|
+
compound_name = "#{params[:real_first_name].to_s.strip} #{params[:real_last_name].to_s.strip}"
|
111
|
+
r.set("name:#{device_name}", compound_name)
|
112
|
+
end
|
113
|
+
if params[:fileToUpload]
|
114
|
+
image_url_returned_from_upload_function = upload(params[:fileToUpload][:filename], params[:fileToUpload][:tempfile], device_name)
|
115
|
+
name_key = "image:" + (compound_name || r.get("name:#{device_name}") || device_name)
|
116
|
+
r.set(name_key, image_url_returned_from_upload_function)
|
117
|
+
end
|
118
|
+
redirect "thanks.html"
|
119
|
+
end
|
120
|
+
|
121
|
+
get "/register" do
|
122
|
+
redirect "register.html"
|
123
|
+
end
|
124
|
+
|
125
|
+
get "/feed", provides: 'text/event-stream' do
|
126
|
+
cross_origin
|
127
|
+
r = Redis.new
|
128
|
+
|
129
|
+
stream :keep_open do |out|
|
130
|
+
loop do
|
131
|
+
if out.closed?
|
132
|
+
break
|
133
|
+
end
|
134
|
+
data = []
|
135
|
+
r.hgetall("current_devices").each do |k,v|
|
136
|
+
name_or_device_name = r.get("name:#{k}") || k
|
137
|
+
data << { device_name: k, name: v, last_seen: (Time.now.to_f * 1000).to_i, avatar: r.get("image:#{name_or_device_name}") }
|
138
|
+
end
|
139
|
+
|
140
|
+
out << "data: #{data.to_json}\n\n"
|
141
|
+
sleep 1
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
post "/information" do
|
147
|
+
#grab current devices on network. Save them to the devices on network key after we make sure that we grab the names that have been added already to the whole list and then save them to the updated hash for redis.
|
148
|
+
devices_on_network = JSON.parse(params[:devices])
|
149
|
+
r = Redis.new
|
150
|
+
old_set = r.hkeys("current_devices")
|
151
|
+
new_set = devices_on_network.keys
|
152
|
+
diff_set = old_set - new_set
|
153
|
+
|
154
|
+
diff_set.each do |d|
|
155
|
+
r.hdel("current_devices", d)
|
156
|
+
end
|
157
|
+
|
158
|
+
devices_on_network.each do |k,v|
|
159
|
+
r.hmset("current_devices", k, r.get("name:#{k}"))
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'sinatra/support'
|
4
|
+
require 'sinatra/json'
|
5
|
+
require 'redis'
|
6
|
+
require 'resolv'
|
7
|
+
require 'sinatra/cross_origin'
|
8
|
+
require 'aws/s3'
|
9
|
+
require 'SecureRandom'
|
10
|
+
require 'mini_magick'
|
11
|
+
|
12
|
+
Encoding.default_external = 'utf-8' if defined?(::Encoding)
|
13
|
+
|
14
|
+
module BenevolentGaze
|
15
|
+
class Kiosk < Sinatra::Base
|
16
|
+
set server: 'thin', connections: []
|
17
|
+
set :bind, '0.0.0.0'
|
18
|
+
set :app_file, __FILE__
|
19
|
+
set :port, ENV['PORT']
|
20
|
+
set :static, true
|
21
|
+
set :public_folder, 'public'
|
22
|
+
@@local_file_system = "insert_local_file_system"
|
23
|
+
|
24
|
+
register Sinatra::CrossOrigin
|
25
|
+
|
26
|
+
configure do
|
27
|
+
unless ENV['AWS_ACCESS_KEY_ID'].empty? || ENV['AWS_SECRET_ACCESS_KEY'].empty? || ENV['AWS_CDN_BUCKET'].empty?
|
28
|
+
USE_AWS = true
|
29
|
+
else
|
30
|
+
USE_AWS = false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
helpers do
|
35
|
+
def upload(filename, file, device_name)
|
36
|
+
doomsday = Time.mktime(2038, 1, 18).to_i
|
37
|
+
if (filename)
|
38
|
+
new_file_name = device_name.to_s + SecureRandom.uuid.to_s + filename
|
39
|
+
bucket = ENV['AWS_CDN_BUCKET']
|
40
|
+
image = MiniMagick::Image.open(file.path)
|
41
|
+
|
42
|
+
animated_gif = `identify -format "%n" "#{file.path}"`.to_i > 1
|
43
|
+
if animated_gif
|
44
|
+
image.repage "0x0"
|
45
|
+
if image.height > image.width
|
46
|
+
image.resize "300"
|
47
|
+
offset = (image.height/2) - 150
|
48
|
+
image.crop("300x300+0+#{offset}")
|
49
|
+
else
|
50
|
+
image.resize "x300"
|
51
|
+
offset = (image.width/2) - 150
|
52
|
+
image.crop("300x300+#{offset}+0")
|
53
|
+
end
|
54
|
+
image << "+repage"
|
55
|
+
else
|
56
|
+
image.auto_orient
|
57
|
+
if image.height > image.width
|
58
|
+
image.resize "300"
|
59
|
+
offset = (image.height/2) - 150
|
60
|
+
image.crop("300x300+0+#{offset}")
|
61
|
+
else
|
62
|
+
image.resize "x300"
|
63
|
+
offset = (image.width/2) - 150
|
64
|
+
image.crop("300x300+#{offset}+0")
|
65
|
+
end
|
66
|
+
image.format "png"
|
67
|
+
end
|
68
|
+
|
69
|
+
if USE_AWS
|
70
|
+
AWS::S3::Base.establish_connection!(
|
71
|
+
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
|
72
|
+
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
|
73
|
+
)
|
74
|
+
AWS::S3::S3Object.store(
|
75
|
+
new_file_name,
|
76
|
+
image.to_blob,
|
77
|
+
bucket,
|
78
|
+
:access => :public_read
|
79
|
+
)
|
80
|
+
image_url = AWS::S3::S3Object.url_for( new_file_name, bucket, :expires => doomsday )
|
81
|
+
else
|
82
|
+
upload_path = @@local_file_system
|
83
|
+
file_on_disk = upload_path + new_file_name
|
84
|
+
File.open(File.expand_path(file_on_disk), "w") do |f|
|
85
|
+
f.write(image.to_blob)
|
86
|
+
end
|
87
|
+
image_url = "images/uploads/" + new_file_name
|
88
|
+
end
|
89
|
+
|
90
|
+
return image_url
|
91
|
+
|
92
|
+
else
|
93
|
+
return nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
get "/" do
|
99
|
+
redirect "index.html"
|
100
|
+
end
|
101
|
+
|
102
|
+
post "/register" do
|
103
|
+
dns = Resolv.new
|
104
|
+
device_name = dns.getname(request.ip)
|
105
|
+
r = Redis.new
|
106
|
+
|
107
|
+
compound_name = nil
|
108
|
+
|
109
|
+
if !params[:real_first_name].empty? || !params[:real_last_name].empty?
|
110
|
+
compound_name = "#{params[:real_first_name].to_s.strip} #{params[:real_last_name].to_s.strip}"
|
111
|
+
r.set("name:#{device_name}", compound_name)
|
112
|
+
end
|
113
|
+
if params[:fileToUpload]
|
114
|
+
image_url_returned_from_upload_function = upload(params[:fileToUpload][:filename], params[:fileToUpload][:tempfile], device_name)
|
115
|
+
name_key = "image:" + (compound_name || r.get("name:#{device_name}") || device_name)
|
116
|
+
r.set(name_key, image_url_returned_from_upload_function)
|
117
|
+
end
|
118
|
+
redirect "thanks.html"
|
119
|
+
end
|
120
|
+
|
121
|
+
get "/register" do
|
122
|
+
redirect "register.html"
|
123
|
+
end
|
124
|
+
|
125
|
+
get "/feed", provides: 'text/event-stream' do
|
126
|
+
cross_origin
|
127
|
+
r = Redis.new
|
128
|
+
|
129
|
+
stream :keep_open do |out|
|
130
|
+
loop do
|
131
|
+
if out.closed?
|
132
|
+
break
|
133
|
+
end
|
134
|
+
data = []
|
135
|
+
r.hgetall("current_devices").each do |k,v|
|
136
|
+
name_or_device_name = r.get("name:#{k}") || k
|
137
|
+
data << { device_name: k, name: v, last_seen: (Time.now.to_f * 1000).to_i, avatar: r.get("image:#{name_or_device_name}") }
|
138
|
+
end
|
139
|
+
|
140
|
+
out << "data: #{data.to_json}\n\n"
|
141
|
+
sleep 1
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
post "/information" do
|
147
|
+
#grab current devices on network. Save them to the devices on network key after we make sure that we grab the names that have been added already to the whole list and then save them to the updated hash for redis.
|
148
|
+
devices_on_network = JSON.parse(params[:devices])
|
149
|
+
r = Redis.new
|
150
|
+
old_set = r.hkeys("current_devices")
|
151
|
+
new_set = devices_on_network.keys
|
152
|
+
diff_set = old_set - new_set
|
153
|
+
|
154
|
+
diff_set.each do |d|
|
155
|
+
r.hdel("current_devices", d)
|
156
|
+
end
|
157
|
+
|
158
|
+
devices_on_network.each do |k,v|
|
159
|
+
r.hmset("current_devices", k, r.get("name:#{k}"))
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'resolv'
|
2
|
+
require 'httparty'
|
3
|
+
|
4
|
+
module BenevolentGaze
|
5
|
+
class Tracker
|
6
|
+
@@old_time = Time.now.to_i
|
7
|
+
|
8
|
+
def self.run!
|
9
|
+
# Run forever
|
10
|
+
while true
|
11
|
+
scan
|
12
|
+
check_time
|
13
|
+
sleep 10
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
private
|
19
|
+
|
20
|
+
def check_time
|
21
|
+
#if ((@@old_time + (30*60)) <= Time.now.to_i)
|
22
|
+
if (@@old_time <= Time.now.to_i)
|
23
|
+
begin
|
24
|
+
#TODO make sure to change the url to read from an environment variable for the correct company url.
|
25
|
+
HTTParty.post( (ENV['BG_COMPANY_URL'] || 'http://localhost:3000/register'), query: { ip: `ifconfig | awk '/inet/ {print $2}' | grep -E '[[:digit:]]{1,3}\\.' | tail -1`.strip + ":#{ENV['IPORT']}/register"})
|
26
|
+
puts "Just sent localhost address to server."
|
27
|
+
rescue
|
28
|
+
puts "Looks like there is something wrong with the endpoint to identify the localhost."
|
29
|
+
end
|
30
|
+
@old_time = Time.now.to_i
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def scan
|
35
|
+
=begin
|
36
|
+
# Look for the network broadcast address
|
37
|
+
broadcast = `ifconfig -a | grep broadcast`.split[-1]
|
38
|
+
|
39
|
+
# puts "Broadcast Address #{broadcast}"
|
40
|
+
unless broadcast =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/
|
41
|
+
puts "#{broadcast} doesn't look correct"
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
|
45
|
+
# Ping the broadcast address 4 times and wait for responses
|
46
|
+
ips = `ping -t 4 #{broadcast}`.split(/\n/).collect do |x|
|
47
|
+
if x =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):/
|
48
|
+
$1
|
49
|
+
else
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
end.select { |x| x && x != broadcast}.sort.uniq
|
53
|
+
|
54
|
+
dns = Resolv.new
|
55
|
+
device_names_and_ip_addresses = {}
|
56
|
+
|
57
|
+
ips.each do |ip|
|
58
|
+
name = dns.getname ip
|
59
|
+
device_names_and_ip_addresses[name] = nil
|
60
|
+
end
|
61
|
+
puts "****************************"
|
62
|
+
=end
|
63
|
+
|
64
|
+
#reintroduction of arp usage for mac addresses - will reintegrate soon.
|
65
|
+
device_name_and_mac_address_hash = {}
|
66
|
+
`arp -a | grep -v "?" | awk '{print $1 "\t" $4}'`.split("\n").each do |a|
|
67
|
+
a = a.split("\t")
|
68
|
+
device_name_and_mac_address_hash[a[0]] = a[1]
|
69
|
+
end
|
70
|
+
|
71
|
+
device_names_hash = {}
|
72
|
+
device_names_arr = `for i in {1..254}; do echo ping -t 4 192.168.1.${i} ; done | parallel -j 0 --no-notice 2> /dev/null | awk '/ttl/ { print $4 }' | sort | uniq | sed 's/://' | xargs -n 1 host | awk '{ print $5 }' | sed 's/\.$//'`.split(/\n/)
|
73
|
+
device_names_arr.each do |d|
|
74
|
+
unless d.match(/Wireless|EPSON/)
|
75
|
+
device_names_hash[d] = nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
puts device_names_hash
|
79
|
+
begin
|
80
|
+
HTTParty.post("http://localhost:#{ENV['IPORT']}/information", query: {devices: device_names_hash.to_json } )
|
81
|
+
rescue
|
82
|
+
puts "Looks like you might not have the Benevolent Gaze gem running"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/website/.gitignore
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
2
|
+
#
|
3
|
+
# If you find yourself ignoring temporary files generated by your text editor
|
4
|
+
# or operating system, you probably want to add a global ignore instead:
|
5
|
+
# git config --global core.excludesfile ~/.gitignore_global
|
6
|
+
|
7
|
+
# Ignore bundler config
|
8
|
+
/.bundle
|
9
|
+
|
10
|
+
# Ignore the build directory
|
11
|
+
/build
|
12
|
+
|
13
|
+
# Ignore cache
|
14
|
+
/.sass-cache
|
15
|
+
/.cache
|
16
|
+
|
17
|
+
# Ignore .DS_store file
|
18
|
+
.DS_Store
|
data/website/Gemfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# If you do not have OpenSSL installed, update
|
2
|
+
# the following line to use "http://" instead
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
gem "middleman", "~>3.3.7"
|
6
|
+
gem "middleman-deploy"
|
7
|
+
gem "middleman-autometatags"
|
8
|
+
gem "middleman-livereload", "~> 3.1.0"
|
9
|
+
gem "bootstrap-sass"
|
10
|
+
gem "jquery-middleman"
|
11
|
+
|
12
|
+
# For faster file watcher updates on Windows:
|
13
|
+
gem "wdm", "~> 0.1.0", :platforms => [:mswin, :mingw]
|
14
|
+
|
15
|
+
# Windows does not come with time zone data
|
16
|
+
gem "tzinfo-data", platforms: [:mswin, :mingw]
|
17
|
+
|
18
|
+
gem "builder", "~> 3.0"
|
19
|
+
|
20
|
+
gem "redcarpet"
|