kinokero 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +44 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +49 -0
- data/Gemfile_mock +8 -0
- data/LICENSE +20 -0
- data/README.md +955 -0
- data/Rakefile +1 -0
- data/console/.ruby-gemset +1 -0
- data/console/.ruby-version +1 -0
- data/console/Gemfile +6 -0
- data/console/Gemfile.lock +63 -0
- data/console/README.md +34 -0
- data/console/config/application_configuration.rb +39 -0
- data/console/config/gcp_seed.yml +73 -0
- data/console/config/kinokero_initializer_template.rb +108 -0
- data/console/console +2 -0
- data/console/irb_console +2 -0
- data/console/lib/appliance_common.rb +73 -0
- data/console/twiga.rb +579 -0
- data/hp-check.log +244 -0
- data/kinokero.gemspec +35 -0
- data/lib/kinokero.rb +183 -0
- data/lib/kinokero/blank.rb +105 -0
- data/lib/kinokero/cloudprint.rb +1159 -0
- data/lib/kinokero/device.rb +6 -0
- data/lib/kinokero/jingle.rb +176 -0
- data/lib/kinokero/log.rb +157 -0
- data/lib/kinokero/printer.rb +313 -0
- data/lib/kinokero/proxy.rb +341 -0
- data/lib/kinokero/ruby_extensions.rb +21 -0
- data/lib/kinokero/sasl_xoauth2.rb +164 -0
- data/lib/kinokero/version.rb +3 -0
- data/lib/proto/cloud_device_description.proto +18 -0
- data/lib/proto/cloud_device_state.proto +30 -0
- data/lib/proto/cloud_device_state_type.proto +20 -0
- data/lib/proto/cloud_device_ui_state.proto +42 -0
- data/lib/proto/cloud_device_ui_state_severity.proto +12 -0
- data/lib/proto/cloud_job_ticket.proto +18 -0
- data/lib/proto/collate.proto +4 -0
- data/lib/proto/collate_ticket_item.proto +5 -0
- data/lib/proto/color.proto +42 -0
- data/lib/proto/color_ticket_item.proto +12 -0
- data/lib/proto/copies.proto +6 -0
- data/lib/proto/copies_ticket_item.proto +5 -0
- data/lib/proto/cover.proto +31 -0
- data/lib/proto/cover_state.proto +25 -0
- data/lib/proto/device_action_cause.proto +19 -0
- data/lib/proto/dpi.proto +27 -0
- data/lib/proto/dpi_ticket_item.proto +13 -0
- data/lib/proto/duplex.proto +15 -0
- data/lib/proto/duplex_ticket_item.proto +8 -0
- data/lib/proto/fit_to_page.proto +20 -0
- data/lib/proto/fit_to_page_ticket_item.proto +8 -0
- data/lib/proto/input_tray_state.proto +31 -0
- data/lib/proto/input_tray_unit.proto +35 -0
- data/lib/proto/job_state.proto +143 -0
- data/lib/proto/local_settings.proto +36 -0
- data/lib/proto/localized_string.proto +119 -0
- data/lib/proto/margins.proto +33 -0
- data/lib/proto/margins_ticket_item.proto +14 -0
- data/lib/proto/marker.proto +62 -0
- data/lib/proto/marker_state.proto +31 -0
- data/lib/proto/media_path.proto +6 -0
- data/lib/proto/media_path_state.proto +25 -0
- data/lib/proto/media_size.proto +216 -0
- data/lib/proto/media_size_ticket_item.proto +17 -0
- data/lib/proto/output_bin_state.proto +31 -0
- data/lib/proto/output_bin_unit.proto +32 -0
- data/lib/proto/page_orientation.proto +16 -0
- data/lib/proto/page_orientation_ticket_item.proto +9 -0
- data/lib/proto/page_range.proto +15 -0
- data/lib/proto/page_range_ticket_item.proto +7 -0
- data/lib/proto/print_job_state.proto +18 -0
- data/lib/proto/print_job_state_diff.proto +13 -0
- data/lib/proto/print_job_ui_state.proto +24 -0
- data/lib/proto/print_ticket_section.proto +30 -0
- data/lib/proto/printer_description_section.proto +107 -0
- data/lib/proto/printer_state_section.proto +49 -0
- data/lib/proto/printer_ui_state_section.proto +39 -0
- data/lib/proto/printing_speed.proto +35 -0
- data/lib/proto/pwg_raster_config.proto +176 -0
- data/lib/proto/range_capability.proto +14 -0
- data/lib/proto/reverse_order.proto +5 -0
- data/lib/proto/reverse_order_ticket_item.proto +5 -0
- data/lib/proto/scanner_description_section.proto +5 -0
- data/lib/proto/scanner_state_section.proto +25 -0
- data/lib/proto/select_capability.proto +31 -0
- data/lib/proto/supported_content_type.proto +12 -0
- data/lib/proto/typed_value_capability.proto +15 -0
- data/lib/proto/vendor_capability.proto +40 -0
- data/lib/proto/vendor_state.proto +26 -0
- data/lib/proto/vendor_ticket_item.proto +9 -0
- data/lib/proto_lib/cloud_device_state.pb.rb +21 -0
- data/lib/proto_lib/cloud_device_state_type.pb.rb +16 -0
- data/lib/proto_lib/cloud_device_ui_state.pb.rb +22 -0
- data/lib/proto_lib/cloud_device_ui_state_severity.pb.rb +17 -0
- data/lib/proto_lib/collate.pb.rb +11 -0
- data/lib/proto_lib/color.pb.rb +31 -0
- data/lib/proto_lib/copies.pb.rb +12 -0
- data/lib/proto_lib/cover.pb.rb +21 -0
- data/lib/proto_lib/cover_state.pb.rb +27 -0
- data/lib/proto_lib/device_action_cause.pb.rb +18 -0
- data/lib/proto_lib/dpi.pb.rb +27 -0
- data/lib/proto_lib/duplex.pb.rb +26 -0
- data/lib/proto_lib/fit_to_page.pb.rb +28 -0
- data/lib/proto_lib/input_tray_state.pb.rb +30 -0
- data/lib/proto_lib/input_tray_unit.pb.rb +25 -0
- data/lib/proto_lib/job_state.pb.rb +99 -0
- data/lib/proto_lib/localized_string.pb.rb +118 -0
- data/lib/proto_lib/margins.pb.rb +30 -0
- data/lib/proto_lib/marker.pb.rb +45 -0
- data/lib/proto_lib/marker_state.pb.rb +30 -0
- data/lib/proto_lib/media_path.pb.rb +11 -0
- data/lib/proto_lib/media_path_state.pb.rb +27 -0
- data/lib/proto_lib/media_size.pb.rb +198 -0
- data/lib/proto_lib/output_bin_state.pb.rb +30 -0
- data/lib/proto_lib/output_bin_unit.pb.rb +22 -0
- data/lib/proto_lib/page_orientation.pb.rb +26 -0
- data/lib/proto_lib/page_range.pb.rb +20 -0
- data/lib/proto_lib/print_job_state_diff.pb.rb +12 -0
- data/lib/proto_lib/printer_description_section.pb.rb +30 -0
- data/lib/proto_lib/printer_state_section.pb.rb +23 -0
- data/lib/proto_lib/printer_ui_state_section.pb.rb +28 -0
- data/lib/proto_lib/printing_speed.pb.rb +21 -0
- data/lib/proto_lib/pwg_raster_config.pb.rb +103 -0
- data/lib/proto_lib/range_capability.pb.rb +19 -0
- data/lib/proto_lib/reverse_order.pb.rb +11 -0
- data/lib/proto_lib/scanner_description_section.pb.rb +10 -0
- data/lib/proto_lib/scanner_state_section.pb.rb +17 -0
- data/lib/proto_lib/select_capability.pb.rb +22 -0
- data/lib/proto_lib/supported_content_type.pb.rb +13 -0
- data/lib/proto_lib/typed_value_capability.pb.rb +19 -0
- data/lib/proto_lib/vendor_capability.pb.rb +23 -0
- data/lib/proto_lib/vendor_state.pb.rb +27 -0
- data/test/.ruby-gemset +1 -0
- data/test/.ruby-version +1 -0
- data/test/Gemfile +68 -0
- data/test/Gemfile.lock +269 -0
- data/test/README.md +2 -0
- data/test/Rakefile +6 -0
- data/test/app/assets/javascripts/application.js +16 -0
- data/test/app/assets/stylesheets/application.css +13 -0
- data/test/app/controllers/application_controller.rb +13 -0
- data/test/app/controllers/home_controller.rb +10 -0
- data/test/app/helpers/application_helper.rb +2 -0
- data/test/app/views/home/index.html.erb +2 -0
- data/test/app/views/home/show.html.erb +2 -0
- data/test/app/views/layouts/application.html.erb +14 -0
- data/test/bin/bundle +3 -0
- data/test/bin/rails +4 -0
- data/test/bin/rake +4 -0
- data/test/config/application.rb +29 -0
- data/test/config/boot.rb +4 -0
- data/test/config/database.yml +25 -0
- data/test/config/environment.rb +5 -0
- data/test/config/environments/development.rb +48 -0
- data/test/config/environments/production.rb +95 -0
- data/test/config/environments/test.rb +42 -0
- data/test/config/initializers/backtrace_silencers.rb +7 -0
- data/test/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/config/initializers/inflections.rb +16 -0
- data/test/config/initializers/mime_types.rb +5 -0
- data/test/config/initializers/secret_token.rb +12 -0
- data/test/config/initializers/session_store.rb +3 -0
- data/test/config/initializers/wrap_parameters.rb +14 -0
- data/test/config/locales/en.yml +23 -0
- data/test/config/routes.rb +65 -0
- data/test/db/development.sqlite3 +0 -0
- data/test/db/migrate/20111012050200_add_sessions_table.rb +12 -0
- data/test/db/schema.rb +26 -0
- data/test/db/seeds.rb +7 -0
- data/test/db/test.sqlite3 +0 -0
- data/test/log/development.log +0 -0
- data/test/log/test.log +0 -0
- data/test/test/controllers/home_controller_test.rb +133 -0
- data/test/test/ctlr_test_helper.rb +7 -0
- data/test/test/fixtures/gcp_seed.yml +51 -0
- data/test/test/models/cloudprint_test.rb +186 -0
- data/test/test/models/jingle_test.rb +44 -0
- data/test/test/models/printer_test.rb +99 -0
- data/test/test/models/proxy_test.rb +102 -0
- data/test/test/test_helper.rb +31 -0
- data/test/test/test_kinokero.rb +234 -0
- metadata +462 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9e46577377eb69a3790e26ee9ca1cd38d6f10db6
|
4
|
+
data.tar.gz: c2728c3ef37b103c29e8eaa93ecb7939625c8f84
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 33dc6cb20865da3daf62d381008229baf29d8afbf85d60224fced64f054f969e6d4cd89d4848faf97a5168b646e8e12acc6b2a5678f2f10a62f42f678bd104e0
|
7
|
+
data.tar.gz: 595b06fbe75c6b83d19f0848e1ed24d29b0ec37a73f5f9e583798655d3aea5158a47ba53c4a7e286fa4f500f2f59100e561b65abbfa188323b6e23c476a6b933
|
data/.gitignore
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.config
|
4
|
+
coverage
|
5
|
+
InstalledFiles
|
6
|
+
lib/bundler/man
|
7
|
+
rdoc
|
8
|
+
spec/reports
|
9
|
+
test/tmp
|
10
|
+
test/version_tmp
|
11
|
+
tmp
|
12
|
+
|
13
|
+
# YARD artifacts
|
14
|
+
.yardoc
|
15
|
+
_yardoc
|
16
|
+
doc/
|
17
|
+
|
18
|
+
|
19
|
+
pkg/*
|
20
|
+
tags
|
21
|
+
|
22
|
+
*.rbc
|
23
|
+
*.sassc
|
24
|
+
.sass-cache
|
25
|
+
capybara-*.html
|
26
|
+
.rspec
|
27
|
+
/.bundle
|
28
|
+
/vendor/bundle
|
29
|
+
/log/*
|
30
|
+
/tmp/*
|
31
|
+
/db/*.sqlite3
|
32
|
+
/public/system/*
|
33
|
+
/coverage/
|
34
|
+
/spec/tmp/*
|
35
|
+
**.orig
|
36
|
+
rerun.txt
|
37
|
+
pickle-email-*.html
|
38
|
+
|
39
|
+
# Vim
|
40
|
+
*.swp
|
41
|
+
*.swo
|
42
|
+
*~
|
43
|
+
|
44
|
+
.keep
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
kinokero
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.0.0-p247
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
kinokero (0.0.1)
|
5
|
+
beefcake
|
6
|
+
faraday
|
7
|
+
faraday-cookie_jar
|
8
|
+
faraday_middleware
|
9
|
+
logger
|
10
|
+
simple_oauth
|
11
|
+
typhoeus
|
12
|
+
|
13
|
+
GEM
|
14
|
+
remote: https://rubygems.org/
|
15
|
+
specs:
|
16
|
+
beefcake (0.5.0)
|
17
|
+
domain_name (0.5.13)
|
18
|
+
unf (>= 0.0.5, < 1.0.0)
|
19
|
+
ethon (0.6.1)
|
20
|
+
ffi (>= 1.3.0)
|
21
|
+
mime-types (~> 1.18)
|
22
|
+
faraday (0.8.8)
|
23
|
+
multipart-post (~> 1.2.0)
|
24
|
+
faraday-cookie_jar (0.0.4)
|
25
|
+
faraday (>= 0.7.4)
|
26
|
+
http-cookie (~> 1.0.0)
|
27
|
+
faraday_middleware (0.9.0)
|
28
|
+
faraday (>= 0.7.4, < 0.9)
|
29
|
+
ffi (1.9.0)
|
30
|
+
http-cookie (1.0.2)
|
31
|
+
domain_name (~> 0.5)
|
32
|
+
logger (1.2.8)
|
33
|
+
mime-types (1.25)
|
34
|
+
multipart-post (1.2.0)
|
35
|
+
rake (10.1.0)
|
36
|
+
simple_oauth (0.2.0)
|
37
|
+
typhoeus (0.6.5)
|
38
|
+
ethon (~> 0.6.1)
|
39
|
+
unf (0.1.2)
|
40
|
+
unf_ext
|
41
|
+
unf_ext (0.0.6)
|
42
|
+
|
43
|
+
PLATFORMS
|
44
|
+
ruby
|
45
|
+
|
46
|
+
DEPENDENCIES
|
47
|
+
bundler (~> 1.3)
|
48
|
+
kinokero!
|
49
|
+
rake
|
data/Gemfile_mock
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Daudi Amani
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,955 @@
|
|
1
|
+
kinokero
|
2
|
+
========
|
3
|
+
|
4
|
+
Complete Google CloudPrint Proxy client. Includes seperate classes to handle
|
5
|
+
the GCP server protocol (Cloudprint), the GCP Jingle notification protocol
|
6
|
+
(Jingle), and a class for interacting with CUPS devices on a linux system
|
7
|
+
(Printer). The Cloudprint class uses a faraday-based http client for
|
8
|
+
interacting with Google CloudPrint Services (GCPS). Persistence is expected to
|
9
|
+
be handled by whatever is invoking Kinokero. Each of these major classes
|
10
|
+
can (more or less) function in a stand-alone manner for low-level
|
11
|
+
cloudprint primitives.
|
12
|
+
|
13
|
+
About this document: I've tried to capture anything and everything
|
14
|
+
relevant to using the gem. This information is not necessarily well organized (yet).
|
15
|
+
Consider it a first draft. If this gem is simply used as a proxy connector
|
16
|
+
(recomended), then usage is much simpler. If instead you only want the
|
17
|
+
GCPS interfaces ( Class Cloudprint ), then you will need more detailed
|
18
|
+
information found in this document.
|
19
|
+
|
20
|
+
_Kinokero_ is swahili for an impala (the animal, not the Chevy model).
|
21
|
+
|
22
|
+
# Kinokero Status
|
23
|
+
|
24
|
+
* The gem is currently at Beta, v0.0.5.
|
25
|
+
* All GCP protocol interactions are working as a GCP2.0 printer
|
26
|
+
* jingle notifications are working.
|
27
|
+
* Files can be cloudprinted remotely.
|
28
|
+
* Verbose mode has extensive logging of everything from a protocol standpoint
|
29
|
+
* I have a makeshift manual command interpreter ('console')
|
30
|
+
which functions as a debug-level persistence calling module for overall
|
31
|
+
testing kinokero. Please see discussion below.
|
32
|
+
* Kinokero uses Ruby threads when polling is required.
|
33
|
+
* Documentation draft completed.
|
34
|
+
* Unit tests completed (for now).
|
35
|
+
|
36
|
+
## Discussion
|
37
|
+
|
38
|
+
GCP documentation is confusingly bad at best and inaccurate and incomplete at worst.
|
39
|
+
There is nothing approaching correct and accurate protocol documentation with
|
40
|
+
complete examples of actual data requests and responses.
|
41
|
+
There are no state diagrams.
|
42
|
+
|
43
|
+
The Chromium Project has a GCP proxy, but the C++ code is the worst code I have
|
44
|
+
ever seen and was almost useless as a reference. Needless to say, the code has
|
45
|
+
no documentation. From a Ruby perspective, the code is horrific and frightening,
|
46
|
+
a Halloween nightmare visited upon the safely slumbering programmer.
|
47
|
+
Is Ruby the only world with packaged interfaces for doing common things like
|
48
|
+
encryption, http client, xmpp client, etc? Compare the code in cloudprint.rb
|
49
|
+
to the spaghetti tangle in the chromium proxy connector.
|
50
|
+
|
51
|
+
Libjingle was touted as necessary; but again, there is no API documentation and
|
52
|
+
numerous sources mentioned the impossibility of getting it working on a linux
|
53
|
+
system.
|
54
|
+
|
55
|
+
The GCP documents do have some Python code, but they are old and outdated and don't
|
56
|
+
match the current protocol. Lately, Google has added numerous disclaimers to the
|
57
|
+
examples (which are not complete GCP examples!) about the code being outdated
|
58
|
+
and to use it as reference only.
|
59
|
+
|
60
|
+
During development, I had to trial-&-error hack my way to get the protocols working.
|
61
|
+
|
62
|
+
I used popular working Ruby gems to make this package DRY:
|
63
|
+
|
64
|
+
* _faraday_ as the http client (and needed faraday middleware)
|
65
|
+
* _xmpp4r_ as an excellent XMPP module (made skipping libjingle easy)
|
66
|
+
* _cups_ as an interface to the linux CUPS system.
|
67
|
+
* _beefcake_ as the protocol buffer handler & compiler
|
68
|
+
|
69
|
+
## Installation
|
70
|
+
|
71
|
+
Add this line to your application's Gemfile:
|
72
|
+
|
73
|
+
```
|
74
|
+
gem 'kinokero'
|
75
|
+
```
|
76
|
+
|
77
|
+
And then execute:
|
78
|
+
|
79
|
+
```
|
80
|
+
$ bundle install
|
81
|
+
```
|
82
|
+
|
83
|
+
Or install it yourself as:
|
84
|
+
|
85
|
+
```
|
86
|
+
$ gem install kinokero
|
87
|
+
```
|
88
|
+
|
89
|
+
## Console
|
90
|
+
|
91
|
+
During development, I needed a convenient setup and testing structure
|
92
|
+
to individually trigger GCP primitives and see traces of the request
|
93
|
+
and result. I'm calling that the "console" and it has no function
|
94
|
+
inherent to the gem, other than a convenient setup and testing
|
95
|
+
apparatus. Rather than having it vanish, I have made it part of the
|
96
|
+
gem superstructure and it can be run indepently, as though it were
|
97
|
+
an application, for calling and testing the gem.
|
98
|
+
|
99
|
+
It is rather crude and no further improvements will be made to it.
|
100
|
+
Nor will I be particularly receptive to issues published against
|
101
|
+
it. I will, however, potentially request its usage to isolate
|
102
|
+
situations for issues made against the core gem itself.
|
103
|
+
|
104
|
+
The console has a simple means of persistence (a seed yaml file)
|
105
|
+
for any printers which are registered. The seed yaml requires,
|
106
|
+
at the least for initial startup, a section of data for the
|
107
|
+
(required) test printer.
|
108
|
+
|
109
|
+
Some of commands have to be issued in a particular order to be
|
110
|
+
useful. This is largely related to the GCP protocol itself.
|
111
|
+
|
112
|
+
### Invocation
|
113
|
+
|
114
|
+
Before invoking, make sure you cd into the console directory
|
115
|
+
and run bundler to install all the required gems.
|
116
|
+
|
117
|
+
```
|
118
|
+
$ cd console
|
119
|
+
$ bundle install
|
120
|
+
```
|
121
|
+
|
122
|
+
You will need to also set up your Google developers API for
|
123
|
+
your proxy and have that information in the following
|
124
|
+
environmental variables (I do it in .bashrc). The samples
|
125
|
+
shown below have been sterilized for security.
|
126
|
+
|
127
|
+
```
|
128
|
+
export GCP_PROXY_API_PROJECT_NBR=407407407407
|
129
|
+
export GCP_PROXY_API_CLIENT_EMAIL="407407407407@developer.gserviceaccount.com"
|
130
|
+
export GCP_PROXY_CLIENT_ID="407407407407-abcd1abcd2abcd3abcd4abcd5abcd5ef.apps.googleusercontent.com"
|
131
|
+
export GCP_PROXY_CLIENT_SECRET="someSECRETencryptedHEREo"
|
132
|
+
```
|
133
|
+
|
134
|
+
The console can be invoked in two ways: the normal way runs
|
135
|
+
the console and then simply exits to the OS when finished.
|
136
|
+
Or it can be run to exit into irb, still maintaining all
|
137
|
+
instantiated objects, similar to the Rails console.
|
138
|
+
|
139
|
+
Currently, both of these run the console with the '-m'
|
140
|
+
switch, which means *manual* connection for each printer.
|
141
|
+
Without that switch, active printers will be automatically
|
142
|
+
connected (jingle connection) to the GCP servers.
|
143
|
+
|
144
|
+
#### normal invocation
|
145
|
+
|
146
|
+
```
|
147
|
+
$ ./console
|
148
|
+
```
|
149
|
+
|
150
|
+
#### exit-to-irb invocation
|
151
|
+
|
152
|
+
```
|
153
|
+
$ ./irb_console
|
154
|
+
```
|
155
|
+
|
156
|
+
### Command syntax
|
157
|
+
|
158
|
+
```
|
159
|
+
<command> [<printer item>]
|
160
|
+
```
|
161
|
+
|
162
|
+
example:
|
163
|
+
|
164
|
+
```
|
165
|
+
register wild
|
166
|
+
```
|
167
|
+
|
168
|
+
will register a printer called "gcp_wild_printer" and persist the data in the "wild" item in the seed yaml file.
|
169
|
+
|
170
|
+
A single word command (listed below) is required.
|
171
|
+
An optional _item keyword_ to identify which printer. If missing,
|
172
|
+
'test' is assumed as the default printer. Most commands are
|
173
|
+
specific to a printer.
|
174
|
+
|
175
|
+
### Console commands
|
176
|
+
|
177
|
+
#### commands which don't require a printer item
|
178
|
+
|
179
|
+
* *help* - the list of commands
|
180
|
+
* *quit* - exit the console
|
181
|
+
* *exit* - exit the console
|
182
|
+
* *save* - writes the internal seed information to the seed file
|
183
|
+
* *devices* - lists Proxy's my_devices hash for all Kinokero devices (lengthy)
|
184
|
+
* *cups* - switches to submode for querying CUPS primitives
|
185
|
+
|
186
|
+
#### commands which do require a printer item
|
187
|
+
|
188
|
+
* *list* - returns GCP response listing GCP parameters for the given printer if registered.
|
189
|
+
* *fetch* - returns GCP job fetch list for given printer
|
190
|
+
* *register* - anonymous register the given printer. if the given printer
|
191
|
+
* *ready* - queries CUPS for the printer and performs a GCP /update command for its status
|
192
|
+
* *refresh* - refreshes the OAUTH2 token for the given printer
|
193
|
+
* *delete* - deletes the given printer from GCP registered list
|
194
|
+
* *connect* - starts a persistent jingle connection for the given printer; tells GCP that printer is now 'on-line' and ready to receive print requests.
|
195
|
+
this is only necessary if the console has been started in manual mode.
|
196
|
+
* *time* - time when OAUTH2 token expires next for given printer
|
197
|
+
* *gcp* - dump of Cloudprint gcp_control hash for given printer
|
198
|
+
|
199
|
+
### CUPS sub-mode commands
|
200
|
+
|
201
|
+
The CUPS sub-mode is for querying the local CUPS system and displaying the results.
|
202
|
+
|
203
|
+
|
204
|
+
* *help* - lists sub-mode commands
|
205
|
+
* *quit* - exit the cups sub-mode
|
206
|
+
* *exit* - exit the cups sub-mode
|
207
|
+
|
208
|
+
* *printers* - displays CUPS printers by name
|
209
|
+
* *default* - displays the CUPS default printer name
|
210
|
+
* *jobs* - displays the last CUPS printer job status structure
|
211
|
+
* *options* - displays the options (attributes) for the default printer
|
212
|
+
* *print* - prints a test page to the default printer
|
213
|
+
* *scan* - displays a polled scan of printer status while printer prints a test page
|
214
|
+
|
215
|
+
### Seed file
|
216
|
+
|
217
|
+
As a minimum, the "test" printer item must be defined. Each printer item can be
|
218
|
+
mapped to the same, or different, CUPS printers on the local system. The file is:
|
219
|
+
<i>console/config/gcp_seed.yml</i>
|
220
|
+
|
221
|
+
Variables (you supply the correct information) are indicated enclosed in angular
|
222
|
+
brackets: <variable name>.
|
223
|
+
|
224
|
+
```
|
225
|
+
test:
|
226
|
+
printer_id: 0
|
227
|
+
item: test
|
228
|
+
cups_alias: <actual CUPS printer name>
|
229
|
+
is_active: false
|
230
|
+
virgin_access: false
|
231
|
+
gcp_printer_name: gcp_test_printer
|
232
|
+
capability_ppd: /etc/cups/ppd/<actual CUPS printer name>.ppd
|
233
|
+
capability_cdd: /etc/cups/cdd/<actual CUPS printer name>.cdd
|
234
|
+
gcp_uuid: <printer serial number>
|
235
|
+
gcp_manufacturer: <printer manufacturer name>
|
236
|
+
gcp_model: <printer model name>
|
237
|
+
gcp_setup_url: <url to a page for setting up the printer>
|
238
|
+
gcp_support_url: <url to a page for supporting the printer>
|
239
|
+
gcp_update_url: <url to a page for updating the printer>
|
240
|
+
gcp_firmware: '<firmware version number>'
|
241
|
+
```
|
242
|
+
|
243
|
+
For legacy purposes, the PPD file name (complete path) is required.
|
244
|
+
From that, please use the Google CDD converter to convert the
|
245
|
+
PPD to CDD (Cloud Device Description) format and save that on your
|
246
|
+
local system. Provide the complete path to that file. The web
|
247
|
+
tool for this is at: https://www.google.com/cloudprint/tools/cdd/cdd.html
|
248
|
+
|
249
|
+
## Gem Structure
|
250
|
+
|
251
|
+
The kinokero overall structure parallels the different levels for the
|
252
|
+
cloudprint protocol.
|
253
|
+
|
254
|
+
<b>Proxy</b> - is the overall, high-level appliance that satisfies the basic
|
255
|
+
functionality of a cloudprint device. This is the expected entry point
|
256
|
+
for an application which also maintains persistence of printer information.
|
257
|
+
The kinokero console (above), for example, functions as a crude
|
258
|
+
persistent application.
|
259
|
+
|
260
|
+
<b>Cloudprint</b> - is the primary interace for issuing commands to
|
261
|
+
Google Cloudprint servers via HTTP POST commands. Proxy functions
|
262
|
+
use these primitives to do their work. The main data structure
|
263
|
+
used here is based off of an options hash termed
|
264
|
+
<i>gcp_control</i> (described below).
|
265
|
+
|
266
|
+
<b>Jingle</b> - is the interface for the gtalk jingle (XMPP) protocol
|
267
|
+
required for asynchronously receiving notification of pending
|
268
|
+
print jobs (uses a callback mechanism). Class Cloudprint
|
269
|
+
directly accesses Jingle, so you probably won't have to be
|
270
|
+
too concerned about it.
|
271
|
+
|
272
|
+
<b>Printer</b> - is the interface to the local OS CUPS system and does any
|
273
|
+
actual printing. It also does device state polling.
|
274
|
+
|
275
|
+
## Threads
|
276
|
+
|
277
|
+
The gem uses several threads to handle asynchronous polling tasks:
|
278
|
+
|
279
|
+
* polling for user interaction when registering a printer
|
280
|
+
* polling device status
|
281
|
+
* jingle connection
|
282
|
+
* jingle callback
|
283
|
+
|
284
|
+
Note: at this point I haven't seen the need for mutex semaphore control
|
285
|
+
over any of the control structures. It might be required in the future.
|
286
|
+
|
287
|
+
## Usage
|
288
|
+
|
289
|
+
Note that the primary example for setting up and using this gem is the
|
290
|
+
console code: <i>console/twiga.rb</i> and all config, setup folders.
|
291
|
+
|
292
|
+
Terms: the cloudprint proxy (or connector) orchestrates the overall GCP
|
293
|
+
interactions to do the higher level tasks such as register or remove a printer,
|
294
|
+
intercept print notifications and print jobs, etc. So the "user" of kinokero is
|
295
|
+
whoever is using the proxy to register and control local printers. It is not
|
296
|
+
the end user trying to print something on a cloud printer.
|
297
|
+
|
298
|
+
### Printer Names, ids, and aliases
|
299
|
+
|
300
|
+
This can potentially be a point of confusion to first time kinokero users,
|
301
|
+
so please pay close attention. Kinokero has been set up so that you can map
|
302
|
+
several cloudprint (logical) devices to a single CUPS (physical) device. The
|
303
|
+
reason you might want to do this is because each logical device can be defined
|
304
|
+
with its own CDD (Cloud Device Description) parameters: such as color vs
|
305
|
+
monochrome, dual-sided vs single-sided, etc. For economic purposes, an
|
306
|
+
organization might want to limit access to the color-capabilities of a
|
307
|
+
laser printer and give out broader access to the monochrome-capability of
|
308
|
+
that same printer. With kinokero, this is theoretically possible to do.
|
309
|
+
|
310
|
+
So let's work backward through the different names and described them and
|
311
|
+
their purpose. The gcp_control hash (later section) maps these all together.
|
312
|
+
|
313
|
+
<b>item:</b> This is the hash key into the @proxy.my_devices hash of all
|
314
|
+
gcp_control hashes being managed by kinokero.
|
315
|
+
|
316
|
+
<b>gcp_cups_alias:</b> This is the printer name as recognized by cups when used
|
317
|
+
to issue a print command.
|
318
|
+
```
|
319
|
+
lp -d <gcp_cups_alias>
|
320
|
+
```
|
321
|
+
|
322
|
+
<b>gcp_printer_name:</b> This is the name by which a cloudprint user sees the
|
323
|
+
printer when it shows up in their cloudprint managed printers list. For example:
|
324
|
+
"Brother MFC-9340CDW".
|
325
|
+
|
326
|
+
<b>gcp_printerid:</b> This is a string issued by GCPS for use in GCPS calls.
|
327
|
+
For example: "d0510370-f36b-356f-1a82-f93c0756a5d9". This also appears in the
|
328
|
+
"advanced details" section of DETAILS for a cloudprint printer in the Manage
|
329
|
+
Printers dashboard.
|
330
|
+
|
331
|
+
<b>printer_id:</b> This is some type of unique id (string or integer) which
|
332
|
+
the user's program (the one which invokes kinokero) uses to access a persistence
|
333
|
+
record for the given logical printer. It could, for example, be a database
|
334
|
+
record number for the given persistence.
|
335
|
+
|
336
|
+
#### Examples
|
337
|
+
```
|
338
|
+
item: color
|
339
|
+
gcp_cups_alias: laserjet_1020w
|
340
|
+
gcp_printer_name: color laser printer
|
341
|
+
gcp_printerid: d0510370-f36b-356f-1a82-f93c0756a5d9
|
342
|
+
printer_id: 509
|
343
|
+
|
344
|
+
item: b&w
|
345
|
+
gcp_cups_alias: laserjet_1020w
|
346
|
+
gcp_printer_name: monochrome laser printer
|
347
|
+
gcp_printerid: cda248c1-e1f5-8066-1e10-3efe078cface
|
348
|
+
printer_id: 510
|
349
|
+
|
350
|
+
item: test
|
351
|
+
gcp_cups_alias: lp_null
|
352
|
+
gcp_printer_name: null_printer
|
353
|
+
gcp_printerid: 8231517c-716d-4b0a-f721-83fdbe52a05d
|
354
|
+
printer_id: 508
|
355
|
+
```
|
356
|
+
|
357
|
+
In these examples we see three logical cloudprint printers
|
358
|
+
defined. The first two map into the same physical CUPS device.
|
359
|
+
The last one maps into a CUPS device, but has actually been
|
360
|
+
defined as follows, so no actual physical device exists.
|
361
|
+
```
|
362
|
+
$ lpadmin -p lp_null -E -v file:///dev/null
|
363
|
+
```
|
364
|
+
|
365
|
+
|
366
|
+
|
367
|
+
### setting up and initializing the gem
|
368
|
+
|
369
|
+
This section will describe the basic first steps of prepping a call to each of the
|
370
|
+
major classes of the kinokero gem: Proxy, Printer, and Cloudprint. Proxy.new is the
|
371
|
+
highest level and in turn invokes Printer.new and Cloudprint.new. So if you're
|
372
|
+
choosing to work at the Proxy level (recommended!), you won't need to worry
|
373
|
+
about the other two.
|
374
|
+
|
375
|
+
For references, see the sections below dealing with the primary gcp_control hash,
|
376
|
+
kinokero global parameters, pre-defined gem constants,
|
377
|
+
and template file for Rails config/initializers usage.
|
378
|
+
|
379
|
+
### Class Proxy
|
380
|
+
Proxy encapsulates everything needed to function as a Google Cloudprint Proxy
|
381
|
+
Connector Client for any number of printer devices which might be connected to the
|
382
|
+
client machine.
|
383
|
+
|
384
|
+
The Proxy has to function correctly even after recovering from power loss or
|
385
|
+
restarting. Thus there has to be a persistence mechanism in place. This
|
386
|
+
mechanism is beyond the scope of the gem and is the invoking program's
|
387
|
+
responsibility.
|
388
|
+
|
389
|
+
At its simpliest, the invoking program accesses Proxy in three ways:
|
390
|
+
|
391
|
+
* Kinokero::Proxy.new - instantiates a Proxy object which consists of a
|
392
|
+
(possible) list of all actively managed cloudprint devices (from the
|
393
|
+
persistence). All active printers are automatically logically connected
|
394
|
+
to GCPS thus showing as "on-line" and ready for printing.
|
395
|
+
* Proxy#do_register - registers a new printer with GCPS and creates an
|
396
|
+
entry in the managed devices list.
|
397
|
+
* Proxy#do_delete - removes a managed printer from GCPS control.
|
398
|
+
|
399
|
+
The sections below show scaffold coding for preparing those calls.
|
400
|
+
|
401
|
+
Note: Any methods not described in the API are not expected to be
|
402
|
+
publicly accessible; in future versions they may become inaccessible.
|
403
|
+
Please do not use.
|
404
|
+
|
405
|
+
#### Class Proxy initialization
|
406
|
+
```ruby
|
407
|
+
|
408
|
+
# build a hash of options for all active & inactive printers
|
409
|
+
# from the persistence memory (in this case a YAML file)
|
410
|
+
# for details on the gcp_control hash, see later sections in this README
|
411
|
+
#
|
412
|
+
def build_device_list()
|
413
|
+
|
414
|
+
load_gcp_seed() # load the YAML seed data
|
415
|
+
|
416
|
+
# prep to build up a hash of gcp_control hashes
|
417
|
+
gcp_control_hash = {}
|
418
|
+
|
419
|
+
@seed_data.each_key do |item|
|
420
|
+
gcp_control_hash[ item ] = @seed_data[ item ].symbolize_keys # strip item into hash with keys
|
421
|
+
end # convert each seed to a device object
|
422
|
+
|
423
|
+
return gcp_control_hash
|
424
|
+
|
425
|
+
end # convert each seed to a device object
|
426
|
+
|
427
|
+
gem_options = {
|
428
|
+
# true if automatically jingle connect active printers from list
|
429
|
+
auto_connect: true,
|
430
|
+
# true if instance-level verbose log trace of all GCPS and jingle requests
|
431
|
+
verbose: true,
|
432
|
+
# true if truncate long responses
|
433
|
+
log_truncate: true,
|
434
|
+
# true if log trace all responses from GCPS
|
435
|
+
log_response: true
|
436
|
+
}
|
437
|
+
|
438
|
+
@proxy = Kinokero::Proxy.new( build_device_list(), gem_options )
|
439
|
+
```
|
440
|
+
|
441
|
+
#### Class Proxy automatic running
|
442
|
+
|
443
|
+
Proxy is the higher level way to do all cloudprint control. If your gem_options
|
444
|
+
have auto_connect set to true, then everything else is automatic for all
|
445
|
+
currently registered printers. As job print notifications are received, the
|
446
|
+
files will be downloaded, printed, deleted, and the job status updated to DONE.
|
447
|
+
|
448
|
+
#### Class Proxy register cloudprint printers
|
449
|
+
This shows the required preparation and invocation to register
|
450
|
+
a new printer as a cloudprint printer managed by the kinokero proxy.
|
451
|
+
This is the only way to register a printer from the proxy. It uses
|
452
|
+
GCPS' anonymous printer registration method (meaning that the owner
|
453
|
+
google account is not known at the time when registration is invoked.
|
454
|
+
The owner must 'claim' the printer using a GCPS-issued token. In the
|
455
|
+
process of claiming the printer, the owner might have to sign in to
|
456
|
+
a Google account, at which point authentication is established and
|
457
|
+
then the proxy can proceed to get OAUTH2 authorization tokens).
|
458
|
+
|
459
|
+
```ruby
|
460
|
+
|
461
|
+
def register_printer_scaffold( any_parameters )
|
462
|
+
new_request = {
|
463
|
+
item: 'name for this item',
|
464
|
+
printer_id: 0, # will be cue to create new record
|
465
|
+
gcp_printer_name: "gcp_#{item}_printer",
|
466
|
+
capability_ppd: 'pathname for the PPD file', # legacy GCP 1.0
|
467
|
+
capability_cdd: 'pathname for the CDD file', # required GCP 2.0
|
468
|
+
cups_alias: 'cups printer name',
|
469
|
+
gcp_uuid: string, # see gcp_control hash below
|
470
|
+
gcp_manufacturer:string, # see gcp_control hash below
|
471
|
+
gcp_model: string, # see gcp_control hash below
|
472
|
+
gcp_setup_url: string, # see gcp_control hash below
|
473
|
+
gcp_support_url: string, # see gcp_control hash below
|
474
|
+
gcp_update_url: string, # see gcp_control hash below
|
475
|
+
gcp_firmware: string, # see gcp_control hash below
|
476
|
+
}
|
477
|
+
|
478
|
+
response = @proxy.do_register( new_request ) do |gcp_control|
|
479
|
+
|
480
|
+
# item_persistence is user-defined means to persist the
|
481
|
+
# GCPS-issued information for a printer
|
482
|
+
# which must be supplied again to the proxy whenever
|
483
|
+
# rebooting
|
484
|
+
# remember to set up a gcp_control[:printer_id] as the
|
485
|
+
# database record number for this new item for any
|
486
|
+
# future need to update persistence (such as on
|
487
|
+
# refresh token
|
488
|
+
item_persistence( gcp_control )
|
489
|
+
|
490
|
+
end # do persist new printer information
|
491
|
+
|
492
|
+
unless response[:success]
|
493
|
+
puts "printer registration failed: #{response[:message]}"
|
494
|
+
end
|
495
|
+
|
496
|
+
end
|
497
|
+
|
498
|
+
```
|
499
|
+
|
500
|
+
#### Class Proxy remove cloudprint printers
|
501
|
+
This shows the required set up for removing a printer from the cloudprint
|
502
|
+
management. Cloudprint spec requires the proxy to offer the user a
|
503
|
+
way to remove a printer from cloudprint management.
|
504
|
+
|
505
|
+
```ruby
|
506
|
+
def remove_printer_scaffold( item )
|
507
|
+
|
508
|
+
@proxy.do_delete( item ) # removes printer associated with item
|
509
|
+
|
510
|
+
# deactivate_item_persistence is user-defined means to
|
511
|
+
# do any persistence cleanup associated with a deactivated item,
|
512
|
+
# including removal from the my_devices hash, if desired.
|
513
|
+
deactivate_item_persistence( @proxy.my_devices, item )
|
514
|
+
end
|
515
|
+
|
516
|
+
```
|
517
|
+
|
518
|
+
#### Class Proxy other API methods
|
519
|
+
These normally won't be needed. They were originally made high-level
|
520
|
+
so that the debugging console could individually trigger an action and
|
521
|
+
the resulting log trace be viewed.
|
522
|
+
|
523
|
+
Format for discussion will be instance method name & invocation, description.
|
524
|
+
Typically returns the body of a json-parsed GCP response hash (they all have
|
525
|
+
response['success'] set to true if no errors). See the GCP documentation for
|
526
|
+
more detail.
|
527
|
+
|
528
|
+
* do_refresh(item) - refreshes the token authorization; update persistence afterwards.
|
529
|
+
* do_list(item) - returns the list of printers as a json-parsed list of hashes in response['printers']
|
530
|
+
* do_connect(item) - manually initiates the jingle connection which will show the
|
531
|
+
printer as on-line to the cloudprint user.
|
532
|
+
* do_fetch_jobs(item) - returns a json-parsed list of gcp job hashes
|
533
|
+
* do_print_jobs(printerid) - fetches, then prints all jobs in queue for given printerid
|
534
|
+
* do_ready_state(item) - tells GCPS that the printer is ready for jobs
|
535
|
+
* item_from_printerid(printerid) - returns the item key associated with the printerid;
|
536
|
+
raises PrinterNotFound exception if nothing matched.
|
537
|
+
* print_gcp_registration_information(response) - prints the necessary GCP-issued information
|
538
|
+
needed for claiming a newly registered printer. Printing occurs on the printer
|
539
|
+
being registered. "response" parameter is the kinokero-generated hash of information
|
540
|
+
required.
|
541
|
+
|
542
|
+
### Class Printer
|
543
|
+
|
544
|
+
This encapsulates all generic CUPS printer interactions.
|
545
|
+
NOTE: if you are using Class Proxy, you will not need to access the
|
546
|
+
cloudprint objects and you will not need the information in this section.
|
547
|
+
You may safely skip this section!
|
548
|
+
|
549
|
+
Note: Any methods not described in the API are not expected to be
|
550
|
+
publicly accessible; in future versions they may become inaccessible.
|
551
|
+
Please do not use.
|
552
|
+
|
553
|
+
#### Printer#start_poll_thread
|
554
|
+
Starts a background thread to periodically poll the printer status
|
555
|
+
and advise GCPS of any changes or error conditions.
|
556
|
+
|
557
|
+
#### Printer#stop_poll_thread
|
558
|
+
Stops the background thread to periodically poll the printer status.
|
559
|
+
|
560
|
+
#### Printer#print_file(file)
|
561
|
+
Prints the file (full path filename) to the object's printer (using
|
562
|
+
cups_alias).
|
563
|
+
|
564
|
+
|
565
|
+
|
566
|
+
### Class Cloudprint
|
567
|
+
|
568
|
+
This encapsulates all low-level calls to GCPS.
|
569
|
+
NOTE: if you are using Class Proxy, you will not need to access the
|
570
|
+
cloudprint objects and you will not need the information in this section.
|
571
|
+
You may safely skip this section!
|
572
|
+
|
573
|
+
Initialization requires the gcp_control hash and the options hash (which
|
574
|
+
controls a few instance settings like verbose, auto_connect, log_truncate, and
|
575
|
+
log_response). A new Cloudprint object is created, a faraday connection is set up,
|
576
|
+
and a Jingle object created if the printer is active.
|
577
|
+
|
578
|
+
Any responses that are labelled "Returns a GCP json-parsed response hash" means
|
579
|
+
that the result is a hash per the GCP documentation, which should be consulted for
|
580
|
+
the fields returned.
|
581
|
+
|
582
|
+
Note: Any methods not described in the API are not expected to be
|
583
|
+
publicly accessible; in future versions they may become inaccessible.
|
584
|
+
Please do not use.
|
585
|
+
|
586
|
+
#### Cloudprint.regsiter_anonymous_printer
|
587
|
+
|
588
|
+
Pass a request hash and a closure block (invoked upon successful registration
|
589
|
+
confirmation). A thread is used to handle the polling of the confirmation status,
|
590
|
+
so execution immediategly returns after starting (but before confirmation) passing
|
591
|
+
back a response hash containing:
|
592
|
+
|
593
|
+
* :success - true if the registration process was successfully begun
|
594
|
+
* :message - error message if not successful
|
595
|
+
* :printer_id - any persistence id that might have been passed
|
596
|
+
* :cups_alias - the cups name of the printer.
|
597
|
+
* :gcp_printer - GCPS printer name (echoed from gcp_control hash)
|
598
|
+
* :gcp_printer_id - GCPS-issued printer id
|
599
|
+
* :gcp_invite_page_url - complete URL for claim printer page
|
600
|
+
* :gcp_easy_reg_url - simple one-click URL to claim the printer
|
601
|
+
* :gcp_auto_invite_url - similar
|
602
|
+
* :gcp_claim_token_url - similar
|
603
|
+
* :gcp_printer_reg_token - token itself for claiming printer
|
604
|
+
|
605
|
+
GCP documentation states that the invoker should print out instructions
|
606
|
+
to the user on how to claim the printer using the information in the
|
607
|
+
response hash.
|
608
|
+
|
609
|
+
All the other class-level methods are invoked from this method and
|
610
|
+
show should not normally be directly accessed by an outside program.
|
611
|
+
|
612
|
+
#### Cloudprint#gtalk_start_connection(&block)
|
613
|
+
Invoke this to establish a jingle connection with GCPS. This will let
|
614
|
+
GCPS know that the printer is on-line and actively seeking jobs.
|
615
|
+
Jingle sets up an asynch notification thread. When a notification is received,
|
616
|
+
the closure block is invoked receiving the printerid (gcp_issued id)
|
617
|
+
for the printer have queued jobs.
|
618
|
+
|
619
|
+
#### Cloudprint#gcp_get_job_file( file_url )
|
620
|
+
Uses the file_url to request the file from GCPS and returns it (the entire
|
621
|
+
file!) as the response. If there was an error, then returns nil.
|
622
|
+
|
623
|
+
#### Cloudprint#gcp_refresh_tokens
|
624
|
+
Requests a refresh of the cloudprint OAUTH2 tokens if expired.
|
625
|
+
Persistence should be updated after returning new info in gcp_control hash.
|
626
|
+
|
627
|
+
#### Cloudprint#gcp_get_printer_fetch( printerid )
|
628
|
+
Returns a GCP json-parsed response hash containing list of jobs pending for a
|
629
|
+
given printer.
|
630
|
+
|
631
|
+
#### Cloudprint#gcp_job_status( jobid, status, nbr_pages )
|
632
|
+
Update the job status. Status should be one of the GCP_JOBSTATE_xxxx constants.
|
633
|
+
nbr_pages is the number of pages that have been printed.
|
634
|
+
|
635
|
+
|
636
|
+
#### Cloudprint#gcp_job_status_abort( jobid, status, nbr_pages )
|
637
|
+
Updates the abort status for a job that failed. Use one of the GCP_USER_ACTION_xxxx
|
638
|
+
constants.
|
639
|
+
|
640
|
+
#### Cloudprint#gcp_get_printer_list
|
641
|
+
Returns a GCP json-parsed response hash containing list of printers.
|
642
|
+
Currently, kinokero only supports one printer per cloudprint object
|
643
|
+
(corresponds to specific OAUTH2 credentials), so the printer list will have
|
644
|
+
only one item.
|
645
|
+
|
646
|
+
|
647
|
+
|
648
|
+
### Class Jingle
|
649
|
+
|
650
|
+
This encapsulates all XMPP interactions with Google's jingle server which
|
651
|
+
delivers asynch notifications about the presence of print jobs. _Jingle_
|
652
|
+
includes Google's extensions to XMPP for this purpose. There really isn't
|
653
|
+
an API here. The _jingle.rb_ code is mainly what's needed to use xmpp4r
|
654
|
+
in a Google Jingle context. Notification callbacks are handled through
|
655
|
+
Ruby's block closure and infer reentreant code.
|
656
|
+
|
657
|
+
NOTE: if you are using Class Proxy, you will not need to access the
|
658
|
+
cloudprint objects and you will not need the information in this section.
|
659
|
+
You may safely skip this section!
|
660
|
+
|
661
|
+
NOTE: Any methods not described in the API are not expected to be
|
662
|
+
publicly accessible; in future versions they may become inaccessible.
|
663
|
+
Please do not use.
|
664
|
+
|
665
|
+
### gcp_control hash
|
666
|
+
|
667
|
+
This is used throughout the gem, so each attribute will be explained here. Most
|
668
|
+
attributes require persistence, meaning that they have to be supplied to the proxy
|
669
|
+
at initialization for any active printers (this occur at a restart/reboot state).
|
670
|
+
|
671
|
+
None of the GCPS-issued items are required when first registering a printer; only
|
672
|
+
the "Items supplied by the proxy user."
|
673
|
+
|
674
|
+
The console uses a yml file (in lieu of any other type of persistence mechanism)
|
675
|
+
for storing and retrieving these values between sessions. The file is at:
|
676
|
+
<i>console/config/gcp_seed.yml</i>.
|
677
|
+
|
678
|
+
GCPS-issued items which need persistence
|
679
|
+
* *gcp_xmpp_jid:* GCPS-issued id for accessing jingle servers
|
680
|
+
* *gcp_confirmation_url:* GCPS-issued url for confirming the printer registration
|
681
|
+
* *gcp_owner_email:* GCPS-issued owner's email
|
682
|
+
|
683
|
+
* *gcp_printerid:* GCPS-issued printer id
|
684
|
+
|
685
|
+
* *gcp_refresh_token:* GCPS-issued used to refresh the OAUTH2 token
|
686
|
+
* *gcp_access_token:* GCPS-issued OAUTH2 token
|
687
|
+
* *gcp_token_expiry_time:* UTC datetime for when the OAUTH2 token expires (thus needing to be refreshed)
|
688
|
+
* *gcp_token_type:* GCPS-issued, used to form the OAUTH2 token
|
689
|
+
|
690
|
+
Items supplied by proxy user
|
691
|
+
* *item:* identifier for this printer item, such as: 'test'
|
692
|
+
* *printer_id:* local persistence id (such as for a database record)
|
693
|
+
* *cups_alias:* printer name from the OS' standpoint (such as registered with CUPS)
|
694
|
+
* *gcp_printer_name:* user-determined name which shows up in cloudprint user's managed printer list
|
695
|
+
|
696
|
+
* *capability_ppd:* complete file pathname for the PPD printer description file (legacy)
|
697
|
+
* *capability_cdd:* complete file pathname for the CCD cloud device description file (gcp v2.0)
|
698
|
+
|
699
|
+
* *gcp_uuid:* printer serial number, such as: 'VND3R11877'
|
700
|
+
* *gcp_manufacturer:* printer manufacturer, such as: 'Hewlett-Packard'
|
701
|
+
* *gcp_model:* printer model, such as: 'LaserJet P1102w'
|
702
|
+
* *gcp_setup_url:* a url for how-to set up the printer
|
703
|
+
* *gcp_support_url:* a url for getting support
|
704
|
+
* *gcp_update_url:* a url for getting updates
|
705
|
+
* *gcp_firmware:* printer firmware version number, such as: '20130703'
|
706
|
+
|
707
|
+
Kinokero-internal usage (persistence required)
|
708
|
+
* *is_active:* set to true after successful registration; false if no longer in use
|
709
|
+
* *virgin_access:* true for initial oauth2 token for a freshly registered printer; false after first refresh
|
710
|
+
|
711
|
+
Future API usage
|
712
|
+
* *message:* last error message saved
|
713
|
+
|
714
|
+
|
715
|
+
### gem configuration
|
716
|
+
|
717
|
+
There are several global parameters which can be set at gem configuration.
|
718
|
+
Default values are provided for each parameter. These are expained below.
|
719
|
+
Many parameters, however, are fixed by Google Cloud Printer documentation demands
|
720
|
+
and should not be changed.
|
721
|
+
|
722
|
+
|
723
|
+
#### configuration in Rails application
|
724
|
+
|
725
|
+
When using kinokero
|
726
|
+
in a Rails application, use the template
|
727
|
+
<i>console/config/kinokero_initializer_template.rb</i>, which
|
728
|
+
shows how to access and change any of these parameters during
|
729
|
+
your rails project initialization.
|
730
|
+
Copy it into your Rails <i>project-name/config/initializers</i>
|
731
|
+
directory, and rename it to: _kinokero.rb_ .
|
732
|
+
|
733
|
+
The template file also contains comments describing each parameter.
|
734
|
+
|
735
|
+
#### configuration in non-Rails application
|
736
|
+
|
737
|
+
You can change these parameters similar to the example below for
|
738
|
+
changing the verbose setting.
|
739
|
+
```ruby
|
740
|
+
Kinokero.verbose = true
|
741
|
+
```
|
742
|
+
|
743
|
+
#### listing of all configuration parameters and defaults
|
744
|
+
|
745
|
+
class Proxy required
|
746
|
+
* *my_proxy_id:* = MY_PROXY_ID # unique name for this running of the GCP connector client
|
747
|
+
* *proxy_client_id:* = ENV["GCP_PROXY_CLIENT_ID"] || 'missing'
|
748
|
+
* *proxy_client_secret:* = ENV["GCP_PROXY_CLIENT_SECRET"] || 'missing'
|
749
|
+
* *proxy_serial_nbr:* = ENV["GCP_PROXY_SERIAL_NBR"] || 'missing'
|
750
|
+
* *verbose:* = false # for any class-level decisions
|
751
|
+
|
752
|
+
class Cloudprint required
|
753
|
+
* *mimetype_oauth:* = MIMETYPE_OAUTH # how to encoade oauth files
|
754
|
+
* *mimetype_ppd:* = MIMETYPE_PPD # how to encode PPD files
|
755
|
+
* *mimetype_cdd:* = MIMETYPE_CDD # how to encode CDD files
|
756
|
+
* *polling_secs:* = POLLING_SECS # secs to sleep before register polling again
|
757
|
+
* *truncate_log:* = TRUNCATE_LOG # number of characters to truncate response logs
|
758
|
+
* *followup_host:* = FOLLOWUP_HOST #
|
759
|
+
* *followup_uri:* = FOLLOWUP_URI #
|
760
|
+
* *gaia_host:* = GAIA_HOST #
|
761
|
+
* *login_uri:* = LOGIN_URI #
|
762
|
+
* *login_url:* = LOGIN_URL #
|
763
|
+
* *gcp_url:* = GCP_URL #
|
764
|
+
* *gcp_service:* = GCP_SERVICE #
|
765
|
+
* *ssl_ca_path:* = SSL_CERT_PATH # SSL certificates path for this machine
|
766
|
+
|
767
|
+
* *authorization_scope:* = AUTHORIZATION_SCOPE #
|
768
|
+
* *authorization_redirect_uri:* = AUTHORIZATION_REDIRECT_URI #
|
769
|
+
* *oauth2_token_endpoint:* = OAUTH2_TOKEN_ENDPOINT #
|
770
|
+
|
771
|
+
class Jingle required
|
772
|
+
* *xmpp_server:* = XMPP_SERVER #
|
773
|
+
* *ns_google_push:* = NS_GOOGLE_PUSH #
|
774
|
+
* *gcp_channel:* = GCP_CHANNEL #
|
775
|
+
|
776
|
+
cups testpage file path
|
777
|
+
* *cups_testpage_file:* = CUPS_TESTPAGE_FILE
|
778
|
+
|
779
|
+
printer device/cups related
|
780
|
+
* *printer_poll_cycle:* = PRINTER_POLL_CYCLE
|
781
|
+
|
782
|
+
#### kinokero global constants used for defaults
|
783
|
+
|
784
|
+
Current constant defaults are defined as follows, with the
|
785
|
+
actual definitions in _lib/kinokero.rb_ .
|
786
|
+
|
787
|
+
```ruby
|
788
|
+
# mimetype for how to encode CDD files
|
789
|
+
MIMETYPE_JSON = 'application/json'
|
790
|
+
MIMETYPE_PROTOBUF = 'application/protobuf'
|
791
|
+
MIMETYPE_GENERAL = 'application/octet-stream'
|
792
|
+
MIMETYPE_CDD = MIMETYPE_GENERAL
|
793
|
+
|
794
|
+
# mimetype for how to encode PPD files
|
795
|
+
MIMETYPE_PPD = 'application/vnd.cups.ppd'
|
796
|
+
|
797
|
+
# number of secs to sleep before polling again
|
798
|
+
POLLING_SECS = 30
|
799
|
+
|
800
|
+
# number of characters before truncate response logs
|
801
|
+
TRUNCATE_LOG = 1000
|
802
|
+
|
803
|
+
# authentication function constants
|
804
|
+
FOLLOWUP_HOST = 'www.google.com/cloudprint'
|
805
|
+
FOLLOWUP_URI = 'select%2Fgaiaauth'
|
806
|
+
GAIA_HOST = 'www.google.com'
|
807
|
+
LOGIN_URI = '/accounts/ServiceLoginAuth'
|
808
|
+
LOGIN_URL = 'https://www.google.com/accounts/ClientLogin'
|
809
|
+
|
810
|
+
# GCP documentation constants
|
811
|
+
AUTHORIZATION_SCOPE = "https://www.googleapis.com/auth/cloudprint"
|
812
|
+
CLIENT_REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob"
|
813
|
+
AUTHORIZATION_REDIRECT_URI = 'oob'
|
814
|
+
OAUTH2_TOKEN_ENDPOINT = "https://accounts.google.com/o/oauth2/token"
|
815
|
+
MIMETYPE_OAUTH = "application/x-pkcs12"
|
816
|
+
|
817
|
+
# The GCP URL path is composed of URL + SERVICE + ACTION
|
818
|
+
# below three are used when testing locally
|
819
|
+
# GCP_URL = 'http://0.0.0.0:3000'
|
820
|
+
# GCP_SERVICE = '/'
|
821
|
+
# GCP_REGISTER = ''
|
822
|
+
GCP_URL = 'https://www.google.com/'
|
823
|
+
GCP_SERVICE = 'cloudprint'
|
824
|
+
|
825
|
+
# jingle constants required
|
826
|
+
|
827
|
+
XMPP_SERVER = "talk.google.com"
|
828
|
+
NS_GOOGLE_PUSH = "google:push"
|
829
|
+
GCP_CHANNEL = "cloudprint.google.com"
|
830
|
+
|
831
|
+
# MY_PROXY_ID is a unique name for this running of the GCP connector client
|
832
|
+
# formed with gem name + machine-node name (expected to be unique)
|
833
|
+
# TODO: make sure machine nodename is unique
|
834
|
+
MY_PROXY_ID = "kinokero::"+`uname -n`.chop
|
835
|
+
|
836
|
+
# SSL certificates path for this machine
|
837
|
+
SSL_CERT_PATH = "/usr/lib/ssl/certs"
|
838
|
+
|
839
|
+
# CUPS system default testpage file
|
840
|
+
CUPS_TESTPAGE_FILE = "/usr/share/cups/data/default-testpage.pdf"
|
841
|
+
|
842
|
+
# printer device status polling cycle (float secs to sleep)
|
843
|
+
PRINTER_POLL_CYCLE = 15 # wait fifteen seconds before recheck status
|
844
|
+
```
|
845
|
+
|
846
|
+
|
847
|
+
## Testing
|
848
|
+
|
849
|
+
Unit Testing is somewhat problematic because the kinokero gem is also a
|
850
|
+
wrapper for interactions with the Google Cloud Print Server (GCPS).
|
851
|
+
GCPS, unfortunately, are not really set up to handle unit testing. There is
|
852
|
+
no sandbox; everything is _live._
|
853
|
+
|
854
|
+
There are several issues associated with this.
|
855
|
+
|
856
|
+
To use unit testing, you'll
|
857
|
+
need to register yourself into the Google API and obtains client id and secret.
|
858
|
+
You'll then have to set these up in your local environment variables.
|
859
|
+
The unit testing for Cloudprint will verify whether these exist or not and
|
860
|
+
fail the unit tests at the outset if not.
|
861
|
+
|
862
|
+
```
|
863
|
+
export GCP_PROXY_CLIENT_ID="407123456789-321ngkabcdefghijklmnooppqrstuvwx.apps.googleusercontent.com"
|
864
|
+
export GCP_PROXY_CLIENT_SECRET="iAMsecretiAMsecretiAMsec"
|
865
|
+
```
|
866
|
+
|
867
|
+
Next, you'll have to create and register a test printer and claim it
|
868
|
+
at some Google account. You can use the console to do that. Then copy
|
869
|
+
and paste the gcp_seed.yml information into the test item area of
|
870
|
+
test/test/fixtures/gcp_seed.yml.
|
871
|
+
|
872
|
+
The next problem is the manually-intensive nature of registering a
|
873
|
+
printer. This isn't conducive to automated tests, so the actual
|
874
|
+
registration of a printer is not currently in the cloudprint_test.rb.
|
875
|
+
|
876
|
+
And finally, a number of GCPS commands require an active on-line
|
877
|
+
printer to fully test. But it is possible to test the _failure_ of
|
878
|
+
various GCPS commands by issueing them against non-existent
|
879
|
+
print jobs and files. At the very least, we can test the command
|
880
|
+
set up, invocation against GCPS, and an unsuccessful GCPS response. This
|
881
|
+
has been done for many of the GCPS actions. These tests are seperated
|
882
|
+
in the test file and a comment marks the start of the section for
|
883
|
+
those tests. That does mean that there will be an OAUTH2 token fetch
|
884
|
+
fail message printed to the log (below) when running the test. This
|
885
|
+
is good and should cause no alarm, since it means the code is working
|
886
|
+
correctly!
|
887
|
+
|
888
|
+
```
|
889
|
+
E, [2014-09-20T12:29:37.479671 #10941] ERROR -- oauth2 token fetch fail: **********************************
|
890
|
+
```
|
891
|
+
|
892
|
+
If you do encounter errors or failures when running the cloudprint tests,
|
893
|
+
you may want to turn on logging by switching the verbose setting. You can
|
894
|
+
change this in the <i>test/test/test_kinokero.rb</i> test helper, line 206:
|
895
|
+
set it to true for a verbose logging; otherwise false for brevity. When
|
896
|
+
logging is verbose (enabled) then ALL requests AND responses to/from
|
897
|
+
GCPS are logged, as well as all Jingle interactions.
|
898
|
+
|
899
|
+
```ruby
|
900
|
+
full_verbose = false # ok to change this setting
|
901
|
+
```
|
902
|
+
|
903
|
+
### Available & planned unit tests
|
904
|
+
|
905
|
+
The list below has the status of all kinokero unit tests.
|
906
|
+
All these unit tests are completed and working.
|
907
|
+
|
908
|
+
* Cloudprint - <i>test/models/cloudprint_test.rb</i>
|
909
|
+
this tests the primary GCPS wrapped interface for all GCPS actions.
|
910
|
+
* Jingle - <i>test/models/jingle_test.rb</i>
|
911
|
+
* Printer - <i>test/models/printer_test.rb</i>
|
912
|
+
* Proxy - <i>test/models/proxy_test.rb</i>
|
913
|
+
|
914
|
+
### Running a unit test
|
915
|
+
|
916
|
+
There is a mini Rails application for the testing environment.
|
917
|
+
From the kinokero gem directory:
|
918
|
+
|
919
|
+
```
|
920
|
+
$cd test # gets you to the mini Rails app
|
921
|
+
$ruby -I test test/models/cloudprint_test.rb
|
922
|
+
```
|
923
|
+
|
924
|
+
or substitute different unit test filenames for <i>cloudprint_test.rb</i>
|
925
|
+
|
926
|
+
## references
|
927
|
+
|
928
|
+
These references are for Google Cloudprint documentation.
|
929
|
+
* Google cloudprint overall site: http://www.google.com/cloudprint/learn/
|
930
|
+
* Google cloudprint developers documentation: https://developers.google.com/cloud-print/docs/overview
|
931
|
+
* Cloud Device Description protocol: https://developers.google.com/cloud-print/docs/cdd
|
932
|
+
* Web tool to automatically convert PPD (or XPS) files in CDD format
|
933
|
+
(required because kinokero supports Cloudprint 2.0): https://www.google.com/cloudprint/tools/cdd/cdd.html
|
934
|
+
* Google Protobuf language: https://developers.google.com/protocol-buffers/docs/overview
|
935
|
+
|
936
|
+
|
937
|
+
## future stuff
|
938
|
+
|
939
|
+
* use a robot account; A gcp developer claims:
|
940
|
+
As long as the same robot account is used for all printers handled by the proxy, you can use just one XMPP connection for notifications for all of the printers. This is mentioned briefly in the documentation at https://developers.google.com/cloud-print/docs/devguide#connectorregistration - just use the robot account from the first registered printer as the 'owner' for all subsequent registrations. In this special case, we make the user who created that robot account the owner of the new printer as well, and use the same robot account credentials for it. This will also resolve the /list issue you mentioned, as calling /list authenticated with the robot account will allow you to see all of the associated printers.
|
941
|
+
* autotest register printer; same developer claims, but I couldn't figure it out:
|
942
|
+
We don't have a special server to test registration against, but you can automate the claim flow for unit tests. It isn't documented externally, but if you use your browser's devtools to look at the requests we make on the claim page, you can see the flow your tests would need to follow to automatically 'claim' a test printer (you can do this with a test Gmail account you register, or with a user's credentials - same for generating the XMPP JID).
|
943
|
+
|
944
|
+
## Contributing
|
945
|
+
|
946
|
+
GCP interaction is, shall we say, delicate. Any changes to Cloudprint or Jingle
|
947
|
+
need to be carefully considered and tested under various conditions.
|
948
|
+
|
949
|
+
1. Fork it
|
950
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
951
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
952
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
953
|
+
5. Run the unit tests and make sure nothing is broken. Supply
|
954
|
+
new unit tests for any added features.
|
955
|
+
6. Create new Pull Request
|