kinokero 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (187) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +44 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +49 -0
  7. data/Gemfile_mock +8 -0
  8. data/LICENSE +20 -0
  9. data/README.md +955 -0
  10. data/Rakefile +1 -0
  11. data/console/.ruby-gemset +1 -0
  12. data/console/.ruby-version +1 -0
  13. data/console/Gemfile +6 -0
  14. data/console/Gemfile.lock +63 -0
  15. data/console/README.md +34 -0
  16. data/console/config/application_configuration.rb +39 -0
  17. data/console/config/gcp_seed.yml +73 -0
  18. data/console/config/kinokero_initializer_template.rb +108 -0
  19. data/console/console +2 -0
  20. data/console/irb_console +2 -0
  21. data/console/lib/appliance_common.rb +73 -0
  22. data/console/twiga.rb +579 -0
  23. data/hp-check.log +244 -0
  24. data/kinokero.gemspec +35 -0
  25. data/lib/kinokero.rb +183 -0
  26. data/lib/kinokero/blank.rb +105 -0
  27. data/lib/kinokero/cloudprint.rb +1159 -0
  28. data/lib/kinokero/device.rb +6 -0
  29. data/lib/kinokero/jingle.rb +176 -0
  30. data/lib/kinokero/log.rb +157 -0
  31. data/lib/kinokero/printer.rb +313 -0
  32. data/lib/kinokero/proxy.rb +341 -0
  33. data/lib/kinokero/ruby_extensions.rb +21 -0
  34. data/lib/kinokero/sasl_xoauth2.rb +164 -0
  35. data/lib/kinokero/version.rb +3 -0
  36. data/lib/proto/cloud_device_description.proto +18 -0
  37. data/lib/proto/cloud_device_state.proto +30 -0
  38. data/lib/proto/cloud_device_state_type.proto +20 -0
  39. data/lib/proto/cloud_device_ui_state.proto +42 -0
  40. data/lib/proto/cloud_device_ui_state_severity.proto +12 -0
  41. data/lib/proto/cloud_job_ticket.proto +18 -0
  42. data/lib/proto/collate.proto +4 -0
  43. data/lib/proto/collate_ticket_item.proto +5 -0
  44. data/lib/proto/color.proto +42 -0
  45. data/lib/proto/color_ticket_item.proto +12 -0
  46. data/lib/proto/copies.proto +6 -0
  47. data/lib/proto/copies_ticket_item.proto +5 -0
  48. data/lib/proto/cover.proto +31 -0
  49. data/lib/proto/cover_state.proto +25 -0
  50. data/lib/proto/device_action_cause.proto +19 -0
  51. data/lib/proto/dpi.proto +27 -0
  52. data/lib/proto/dpi_ticket_item.proto +13 -0
  53. data/lib/proto/duplex.proto +15 -0
  54. data/lib/proto/duplex_ticket_item.proto +8 -0
  55. data/lib/proto/fit_to_page.proto +20 -0
  56. data/lib/proto/fit_to_page_ticket_item.proto +8 -0
  57. data/lib/proto/input_tray_state.proto +31 -0
  58. data/lib/proto/input_tray_unit.proto +35 -0
  59. data/lib/proto/job_state.proto +143 -0
  60. data/lib/proto/local_settings.proto +36 -0
  61. data/lib/proto/localized_string.proto +119 -0
  62. data/lib/proto/margins.proto +33 -0
  63. data/lib/proto/margins_ticket_item.proto +14 -0
  64. data/lib/proto/marker.proto +62 -0
  65. data/lib/proto/marker_state.proto +31 -0
  66. data/lib/proto/media_path.proto +6 -0
  67. data/lib/proto/media_path_state.proto +25 -0
  68. data/lib/proto/media_size.proto +216 -0
  69. data/lib/proto/media_size_ticket_item.proto +17 -0
  70. data/lib/proto/output_bin_state.proto +31 -0
  71. data/lib/proto/output_bin_unit.proto +32 -0
  72. data/lib/proto/page_orientation.proto +16 -0
  73. data/lib/proto/page_orientation_ticket_item.proto +9 -0
  74. data/lib/proto/page_range.proto +15 -0
  75. data/lib/proto/page_range_ticket_item.proto +7 -0
  76. data/lib/proto/print_job_state.proto +18 -0
  77. data/lib/proto/print_job_state_diff.proto +13 -0
  78. data/lib/proto/print_job_ui_state.proto +24 -0
  79. data/lib/proto/print_ticket_section.proto +30 -0
  80. data/lib/proto/printer_description_section.proto +107 -0
  81. data/lib/proto/printer_state_section.proto +49 -0
  82. data/lib/proto/printer_ui_state_section.proto +39 -0
  83. data/lib/proto/printing_speed.proto +35 -0
  84. data/lib/proto/pwg_raster_config.proto +176 -0
  85. data/lib/proto/range_capability.proto +14 -0
  86. data/lib/proto/reverse_order.proto +5 -0
  87. data/lib/proto/reverse_order_ticket_item.proto +5 -0
  88. data/lib/proto/scanner_description_section.proto +5 -0
  89. data/lib/proto/scanner_state_section.proto +25 -0
  90. data/lib/proto/select_capability.proto +31 -0
  91. data/lib/proto/supported_content_type.proto +12 -0
  92. data/lib/proto/typed_value_capability.proto +15 -0
  93. data/lib/proto/vendor_capability.proto +40 -0
  94. data/lib/proto/vendor_state.proto +26 -0
  95. data/lib/proto/vendor_ticket_item.proto +9 -0
  96. data/lib/proto_lib/cloud_device_state.pb.rb +21 -0
  97. data/lib/proto_lib/cloud_device_state_type.pb.rb +16 -0
  98. data/lib/proto_lib/cloud_device_ui_state.pb.rb +22 -0
  99. data/lib/proto_lib/cloud_device_ui_state_severity.pb.rb +17 -0
  100. data/lib/proto_lib/collate.pb.rb +11 -0
  101. data/lib/proto_lib/color.pb.rb +31 -0
  102. data/lib/proto_lib/copies.pb.rb +12 -0
  103. data/lib/proto_lib/cover.pb.rb +21 -0
  104. data/lib/proto_lib/cover_state.pb.rb +27 -0
  105. data/lib/proto_lib/device_action_cause.pb.rb +18 -0
  106. data/lib/proto_lib/dpi.pb.rb +27 -0
  107. data/lib/proto_lib/duplex.pb.rb +26 -0
  108. data/lib/proto_lib/fit_to_page.pb.rb +28 -0
  109. data/lib/proto_lib/input_tray_state.pb.rb +30 -0
  110. data/lib/proto_lib/input_tray_unit.pb.rb +25 -0
  111. data/lib/proto_lib/job_state.pb.rb +99 -0
  112. data/lib/proto_lib/localized_string.pb.rb +118 -0
  113. data/lib/proto_lib/margins.pb.rb +30 -0
  114. data/lib/proto_lib/marker.pb.rb +45 -0
  115. data/lib/proto_lib/marker_state.pb.rb +30 -0
  116. data/lib/proto_lib/media_path.pb.rb +11 -0
  117. data/lib/proto_lib/media_path_state.pb.rb +27 -0
  118. data/lib/proto_lib/media_size.pb.rb +198 -0
  119. data/lib/proto_lib/output_bin_state.pb.rb +30 -0
  120. data/lib/proto_lib/output_bin_unit.pb.rb +22 -0
  121. data/lib/proto_lib/page_orientation.pb.rb +26 -0
  122. data/lib/proto_lib/page_range.pb.rb +20 -0
  123. data/lib/proto_lib/print_job_state_diff.pb.rb +12 -0
  124. data/lib/proto_lib/printer_description_section.pb.rb +30 -0
  125. data/lib/proto_lib/printer_state_section.pb.rb +23 -0
  126. data/lib/proto_lib/printer_ui_state_section.pb.rb +28 -0
  127. data/lib/proto_lib/printing_speed.pb.rb +21 -0
  128. data/lib/proto_lib/pwg_raster_config.pb.rb +103 -0
  129. data/lib/proto_lib/range_capability.pb.rb +19 -0
  130. data/lib/proto_lib/reverse_order.pb.rb +11 -0
  131. data/lib/proto_lib/scanner_description_section.pb.rb +10 -0
  132. data/lib/proto_lib/scanner_state_section.pb.rb +17 -0
  133. data/lib/proto_lib/select_capability.pb.rb +22 -0
  134. data/lib/proto_lib/supported_content_type.pb.rb +13 -0
  135. data/lib/proto_lib/typed_value_capability.pb.rb +19 -0
  136. data/lib/proto_lib/vendor_capability.pb.rb +23 -0
  137. data/lib/proto_lib/vendor_state.pb.rb +27 -0
  138. data/test/.ruby-gemset +1 -0
  139. data/test/.ruby-version +1 -0
  140. data/test/Gemfile +68 -0
  141. data/test/Gemfile.lock +269 -0
  142. data/test/README.md +2 -0
  143. data/test/Rakefile +6 -0
  144. data/test/app/assets/javascripts/application.js +16 -0
  145. data/test/app/assets/stylesheets/application.css +13 -0
  146. data/test/app/controllers/application_controller.rb +13 -0
  147. data/test/app/controllers/home_controller.rb +10 -0
  148. data/test/app/helpers/application_helper.rb +2 -0
  149. data/test/app/views/home/index.html.erb +2 -0
  150. data/test/app/views/home/show.html.erb +2 -0
  151. data/test/app/views/layouts/application.html.erb +14 -0
  152. data/test/bin/bundle +3 -0
  153. data/test/bin/rails +4 -0
  154. data/test/bin/rake +4 -0
  155. data/test/config/application.rb +29 -0
  156. data/test/config/boot.rb +4 -0
  157. data/test/config/database.yml +25 -0
  158. data/test/config/environment.rb +5 -0
  159. data/test/config/environments/development.rb +48 -0
  160. data/test/config/environments/production.rb +95 -0
  161. data/test/config/environments/test.rb +42 -0
  162. data/test/config/initializers/backtrace_silencers.rb +7 -0
  163. data/test/config/initializers/filter_parameter_logging.rb +4 -0
  164. data/test/config/initializers/inflections.rb +16 -0
  165. data/test/config/initializers/mime_types.rb +5 -0
  166. data/test/config/initializers/secret_token.rb +12 -0
  167. data/test/config/initializers/session_store.rb +3 -0
  168. data/test/config/initializers/wrap_parameters.rb +14 -0
  169. data/test/config/locales/en.yml +23 -0
  170. data/test/config/routes.rb +65 -0
  171. data/test/db/development.sqlite3 +0 -0
  172. data/test/db/migrate/20111012050200_add_sessions_table.rb +12 -0
  173. data/test/db/schema.rb +26 -0
  174. data/test/db/seeds.rb +7 -0
  175. data/test/db/test.sqlite3 +0 -0
  176. data/test/log/development.log +0 -0
  177. data/test/log/test.log +0 -0
  178. data/test/test/controllers/home_controller_test.rb +133 -0
  179. data/test/test/ctlr_test_helper.rb +7 -0
  180. data/test/test/fixtures/gcp_seed.yml +51 -0
  181. data/test/test/models/cloudprint_test.rb +186 -0
  182. data/test/test/models/jingle_test.rb +44 -0
  183. data/test/test/models/printer_test.rb +99 -0
  184. data/test/test/models/proxy_test.rb +102 -0
  185. data/test/test/test_helper.rb +31 -0
  186. data/test/test/test_kinokero.rb +234 -0
  187. metadata +462 -0
@@ -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
@@ -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
@@ -0,0 +1 @@
1
+ kinokero
@@ -0,0 +1 @@
1
+ ruby-2.0.0-p247
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby "2.0.0"
4
+
5
+ # Specify your gem's dependencies in kinokero.gemspec
6
+ gemspec
@@ -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
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby "2.0.0"
4
+
5
+ gem 'faraday'
6
+ gem 'typhoeus'
7
+
8
+
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.
@@ -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