jsgui3-server 0.0.121 → 0.0.123

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. package/.vscode/settings.json +6 -0
  2. package/README.md +10 -10
  3. package/controls/Active_HTML_Document.js +116 -116
  4. package/controls/README.md +7 -7
  5. package/controls/page/admin.js +74 -74
  6. package/controls/panel/admin.js +11 -11
  7. package/examples/_css/basic.css +913 -913
  8. package/examples/_css/database-control.css +51 -51
  9. package/examples/_css/jsgui.css +66 -66
  10. package/examples/_css/multi-layout.css +23 -23
  11. package/examples/_css/style.css +1669 -1669
  12. package/examples/_css/top-and-bottom-bars.css +54 -54
  13. package/examples/box/1) square box/client.js +188 -188
  14. package/examples/box/1) square box/server.js +112 -112
  15. package/examples/box/2) twenty square boxes/css flex wrap/client.js +112 -248
  16. package/examples/box/2) twenty square boxes/css flex wrap/server.js +39 -112
  17. package/examples/box/3) twenty selectable square boxes/css flex wrap/client.js +129 -0
  18. package/examples/{controls/15) window, text field → box/3) twenty selectable square boxes/css flex wrap}/server.js +38 -38
  19. package/examples/boxes/square_boxes.js +45 -48
  20. package/examples/boxes/square_boxes_client.js +132 -136
  21. package/examples/client-side-popup-menu-button.html +93 -93
  22. package/examples/color_palette.js +51 -51
  23. package/examples/color_palette_client.js +95 -95
  24. package/examples/controls/1) window/client.js +186 -186
  25. package/examples/controls/1) window/server.js +117 -117
  26. package/examples/controls/10) window, mirrored text inputs/client.js +118 -320
  27. package/examples/controls/10) window, mirrored text inputs/server.js +37 -117
  28. package/examples/controls/11) window, mirrored text fields/client.js +493 -251
  29. package/examples/controls/11) window, mirrored text fields/server.js +117 -117
  30. package/examples/controls/11b) window, shared Data_Object model mirrored text fields/client.js +613 -331
  31. package/examples/controls/11b) window, shared Data_Object model mirrored text fields/server.js +117 -117
  32. package/examples/controls/11c) window, shared Data_Value model mirrored text fields/client.js +617 -617
  33. package/examples/controls/11c) window, shared Data_Value model mirrored text fields/server.js +117 -117
  34. package/examples/controls/11d) window, shared model mirrored integer text fields/client.js +611 -280
  35. package/examples/controls/11d) window, shared model mirrored integer text fields/server.js +134 -22
  36. package/examples/controls/12) window, Select_Options control/client.js +66 -452
  37. package/examples/controls/12) window, Select_Options control/server.js +19 -117
  38. package/examples/controls/13) window, Dropdown_Menu control/client.js +66 -0
  39. package/examples/controls/13) window, Dropdown_Menu control/server.js +20 -0
  40. package/examples/controls/2) two windows/client.js +193 -193
  41. package/examples/controls/2) two windows/server.js +113 -113
  42. package/examples/controls/3) five windows/client.js +217 -217
  43. package/examples/controls/3) five windows/server.js +116 -115
  44. package/examples/controls/4) window, tabbed panel/client.js +54 -225
  45. package/examples/controls/4) window, tabbed panel/server.js +17 -117
  46. package/examples/controls/5) window, grid/client.js +204 -484
  47. package/examples/controls/5) window, grid/server.js +117 -119
  48. package/examples/controls/6) window, color_palette/client.js +68 -204
  49. package/examples/controls/6) window, color_palette/server.js +117 -117
  50. package/examples/controls/7) window, month_view/client.js +40 -231
  51. package/examples/controls/7) window, month_view/server.js +117 -117
  52. package/examples/controls/8) window, checkbox/client.js +33 -209
  53. package/examples/controls/8) window, checkbox/server.js +117 -117
  54. package/examples/controls/9) window, date picker/client.js +76 -303
  55. package/examples/controls/9) window, date picker/server.js +117 -117
  56. package/examples/controls/9b) window, shared data.model mirrored date pickers/README.md +51 -0
  57. package/examples/controls/9b) window, shared data.model mirrored date pickers/client.js +83 -398
  58. package/examples/controls/9b) window, shared data.model mirrored date pickers/server.js +117 -117
  59. package/examples/controls/__old/_html-server-color-palette.js +114 -114
  60. package/examples/controls/__old/html-server-combo-box.js +104 -104
  61. package/examples/controls/__old/html-server-list.js +98 -98
  62. package/examples/controls/__old/html-server-popup-menu-button.js +114 -114
  63. package/examples/controls/__old/html-server-start-stop-toggle-button.js +146 -146
  64. package/examples/controls/__old/scs-arrow-button.js +36 -36
  65. package/examples/controls/__old/scs-date-picker.js +157 -157
  66. package/examples/controls/__old/scs-file-browser.js +82 -82
  67. package/examples/controls/__old/scs-item.js +159 -159
  68. package/examples/controls/__old/scs-month-arrow-selector.js +126 -126
  69. package/examples/controls/__old/scs-month-view.js +94 -94
  70. package/examples/controls/__old/scs-start-stop-toggle-button.js +40 -40
  71. package/examples/controls/__old/scs-tree.js +49 -49
  72. package/examples/controls/__old/scs-year-arrow-selector.js +127 -127
  73. package/examples/demos/date-picker.js +119 -119
  74. package/examples/demos/explain-encapsulation.js +9 -9
  75. package/examples/demos/resizing.js +35 -35
  76. package/examples/demos/server_time.js +6 -6
  77. package/examples/grids/grid_1.js +45 -45
  78. package/examples/grids/grid_1_client.js +329 -329
  79. package/examples/html-rendering.js +20 -20
  80. package/examples/html-server.js +105 -105
  81. package/examples/introducing jsgui3/server.js +110 -110
  82. package/examples/mx_display/mx_display_1.js +45 -45
  83. package/examples/mx_display/mx_display_1_client.js +444 -444
  84. package/fs2.js +1836 -1836
  85. package/http/responders/HTTP_Responder.js +15 -15
  86. package/http/responders/static/Static_Route_HTTP_Responder.js +105 -105
  87. package/module.js +34 -34
  88. package/old/_single-control-server.js +418 -418
  89. package/old/single-control-server.js +368 -368
  90. package/old/single-page-app.js +131 -131
  91. package/package.json +42 -42
  92. package/page-context.js +92 -92
  93. package/publishers/helpers/assigners/Assigner.js +10 -10
  94. package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +150 -150
  95. package/publishers/helpers/assigners/static-headers/Single_Control_Webpage_Server_Static_Headers_Assigner.js +109 -109
  96. package/publishers/helpers/assigners/static-routes/Single_Control_Webpage_Server_Static_Routes_Assigner.js +91 -91
  97. package/publishers/helpers/assigners/static-uncompressed-response-buffers/Single_Control_Webpage_Server_Static_Uncompressed_Response_Buffers_Assigner.js +104 -104
  98. package/publishers/helpers/preparers/static/bundle/Ready_To_Serve_Preparer.js +18 -18
  99. package/publishers/helpers/preparers/static/bundle/Static_Routes_Responses_Webpage_Bundle_Preparer.js +44 -44
  100. package/publishers/http-function-publisher.js +212 -212
  101. package/publishers/http-html-page-publisher.js +5 -5
  102. package/publishers/http-html-publisher.js +24 -24
  103. package/publishers/http-js-publisher.js +135 -135
  104. package/publishers/http-observable-publisher.js +124 -124
  105. package/publishers/http-publisher.js +53 -53
  106. package/publishers/http-resource-publisher.js +325 -325
  107. package/publishers/http-webpage-publisher.js +659 -658
  108. package/publishers/http-webpageorsite-publisher.js +343 -343
  109. package/publishers/http-website-publisher.js +640 -640
  110. package/publishers/notes.md +9 -9
  111. package/resources/README.md +16 -16
  112. package/resources/_old_website-javascript-resource.js +994 -994
  113. package/resources/_old_website-resource.js +507 -507
  114. package/resources/compile/server-resource-compilation.js +43 -43
  115. package/resources/data-resource.js +118 -118
  116. package/resources/fs-resource.js +146 -146
  117. package/resources/jsbuilder/Abstract_Single_Declaration.js +105 -105
  118. package/resources/jsbuilder/Abstract_Single_Declaration_Sequence.js +42 -42
  119. package/resources/jsbuilder/JS_AST/JS_AST_Abstract_Node.js +61 -61
  120. package/resources/jsbuilder/JS_AST/JS_AST_Abstract_Node_Group.js +41 -41
  121. package/resources/jsbuilder/JS_AST/JS_AST_Group_Shared.js +61 -61
  122. package/resources/jsbuilder/JS_AST/JS_AST_Node.js +93 -93
  123. package/resources/jsbuilder/JS_AST/JS_AST_Node_0-Core.js +253 -253
  124. package/resources/jsbuilder/JS_AST/JS_AST_Node_1-Babel.js +337 -337
  125. package/resources/jsbuilder/JS_AST/JS_AST_Node_10-Changing.js +39 -39
  126. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.1-Child.js +96 -96
  127. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.2-Parent.js +37 -37
  128. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.3-Ancestor.js +61 -61
  129. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.2-Inner.js +43 -43
  130. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.3-All.js +72 -72
  131. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.4-Sibling.js +92 -92
  132. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.5-Available_In_Scope.js +29 -29
  133. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.9-Signature.js +116 -116
  134. package/resources/jsbuilder/JS_AST/JS_AST_Node_3-Basics.js +159 -159
  135. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.0-Basics_First.js +178 -178
  136. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.1-Basics_Second.js +87 -87
  137. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.99-Basics_Last.js +91 -91
  138. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.1-Basics_Each.js +136 -136
  139. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.1.5-Basics_Count.js +73 -73
  140. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.2-Basics_Filter.js +39 -39
  141. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.3-Basics_Collect.js +85 -85
  142. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.4-Basics_Select.js +42 -42
  143. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.5-Basics_Find.js +40 -40
  144. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.6-Basics_Callmap.js +54 -54
  145. package/resources/jsbuilder/JS_AST/JS_AST_Node_4.0-Index_Indexes.js +45 -45
  146. package/resources/jsbuilder/JS_AST/JS_AST_Node_4.1-Index.js +343 -343
  147. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.0-Category.js +38 -38
  148. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.1-Category_Identifier.js +30 -30
  149. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.2-Category_Literal.js +28 -28
  150. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.3-Category_Expression.js +26 -26
  151. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.4-Category_Pattern.js +8 -8
  152. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.5-Category_Declaration.js +43 -43
  153. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.6-Category_Statement.js +21 -21
  154. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.0-Type.js +89 -89
  155. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.1-Type_Class_Declaration.js +8 -8
  156. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.2-Type_Variable_Declaration.js +27 -27
  157. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.3-Type_Variable_Declarator.js +28 -28
  158. package/resources/jsbuilder/JS_AST/JS_AST_Node_7-Query.js +736 -736
  159. package/resources/jsbuilder/JS_AST/JS_AST_Node_8-Features.js +64 -64
  160. package/resources/jsbuilder/JS_AST/JS_AST_Node_9-Planning.js +31 -31
  161. package/resources/jsbuilder/JS_AST/JS_AST_Node_Arrangement.js +15 -15
  162. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Declared_Object.js +305 -305
  163. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature.js +77 -77
  164. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature_Declaration.js +248 -248
  165. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature_Declarator.js +138 -138
  166. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature.js +10 -10
  167. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature_Exported.js +100 -100
  168. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature_Exports.js +60 -60
  169. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Interpreted.js +179 -179
  170. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/_JSGUI_Root_Node_Interpreted.js +43 -43
  171. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/special_case_objectassign_to_object.js +12 -12
  172. package/resources/jsbuilder/JS_AST/JS_AST_Node_Group.js +35 -35
  173. package/resources/jsbuilder/JS_AST/JS_AST_Operation.js +11 -11
  174. package/resources/jsbuilder/JS_AST/JS_AST_Operation_On_Relationship.js +31 -31
  175. package/resources/jsbuilder/JS_AST/JS_AST_Ordered_Relationship_Node_To_Group.js +37 -37
  176. package/resources/jsbuilder/JS_AST/JS_AST_Ordinal.js +39 -39
  177. package/resources/jsbuilder/JS_AST/JS_AST_Ordinal_Relationship.js +25 -25
  178. package/resources/jsbuilder/JS_AST/JS_AST_Relationship_Node_To_Group.js +200 -200
  179. package/resources/jsbuilder/JS_AST/JS_AST_Relationship_Node_Within_Group_To_Node.js +43 -43
  180. package/resources/jsbuilder/JS_AST/_JS_AST_Node_3.8-Query_Features.js +76 -76
  181. package/resources/jsbuilder/JS_AST/query/enable_array_as_queryable.js +227 -227
  182. package/resources/jsbuilder/JS_AST/query/find_object_keys.js +404 -404
  183. package/resources/jsbuilder/JS_AST/query/node_queries.js +8 -8
  184. package/resources/jsbuilder/JS_AST/query/root_query_identidy.js +11 -11
  185. package/resources/jsbuilder/JS_AST_Node_Extended/JSGUI_Singular_Declaration.js +85 -85
  186. package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Declaration.js +123 -123
  187. package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Extended.js +87 -87
  188. package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Extended_0-Core.js +10 -10
  189. package/resources/jsbuilder/JS_Builder.js +10 -10
  190. package/resources/jsbuilder/JS_File/Feature/JS_File_Declared_Object.js +31 -31
  191. package/resources/jsbuilder/JS_File/Feature/JS_File_Exported_Object_Info.js +25 -25
  192. package/resources/jsbuilder/JS_File/Feature/JS_File_Exports.js +78 -78
  193. package/resources/jsbuilder/JS_File/Feature/JS_File_Feature.js +17 -17
  194. package/resources/jsbuilder/JS_File/Feature/JS_File_Imported_Object_Info.js +25 -25
  195. package/resources/jsbuilder/JS_File/Feature/JS_File_Imports.js +8 -8
  196. package/resources/jsbuilder/JS_File/JS_File.js +12 -12
  197. package/resources/jsbuilder/JS_File/JS_File_0-Core.js +202 -202
  198. package/resources/jsbuilder/JS_File/JS_File_1-Early_Parse.js +175 -175
  199. package/resources/jsbuilder/JS_File/JS_File_2-Babel.js +81 -81
  200. package/resources/jsbuilder/JS_File/JS_File_3-JS_AST_Node.js +86 -86
  201. package/resources/jsbuilder/JS_File/JS_File_4-Query.js +413 -413
  202. package/resources/jsbuilder/JS_File/JS_File_4.1-Query_Features.js +414 -414
  203. package/resources/jsbuilder/JS_File/JS_File_5-Planning.js +59 -59
  204. package/resources/jsbuilder/JS_File/JS_File_6-Changing.js +24 -24
  205. package/resources/jsbuilder/JS_File/JS_File_Export_Reference.js +12 -12
  206. package/resources/jsbuilder/JS_File/JS_File_Import_Reference.js +23 -23
  207. package/resources/jsbuilder/JS_File/JS_File_Import_References.js +31 -31
  208. package/resources/jsbuilder/JS_File/JS_File_Processor.js +16 -16
  209. package/resources/jsbuilder/JS_File/JS_Files.js +15 -15
  210. package/resources/jsbuilder/Module.js +14 -14
  211. package/resources/jsbuilder/Platform.js +13 -13
  212. package/resources/jsbuilder/Platforms.js +69 -69
  213. package/resources/jsbuilder/Project.js +109 -109
  214. package/resources/jsbuilder/Reference.js +1 -1
  215. package/resources/jsbuilder/Reference_Sequence.js +16 -16
  216. package/resources/jsbuilder/Scope.js +29 -29
  217. package/resources/jsbuilder/Variable_Name_Provider.js +42 -42
  218. package/resources/jsbuilder/_JS_File.js +225 -225
  219. package/resources/jsbuilder/ast_query.js +20 -20
  220. package/resources/jsbuilder/babel/babel_consts.js +162 -162
  221. package/resources/jsbuilder/babel/babel_node_tools.js +541 -541
  222. package/resources/jsbuilder/babel/deep_iterate/deep_iterate_babel.js +923 -904
  223. package/resources/jsbuilder/build.js +16 -16
  224. package/resources/jsbuilder/platform_notes.md +66 -66
  225. package/resources/jsbuilder/test/test_ast_node.js +381 -381
  226. package/resources/jsbuilder/test/test_js_file.js +303 -303
  227. package/resources/jsbuilder/test/test_project.js +157 -157
  228. package/resources/local-server-info-resource.js +96 -96
  229. package/resources/notes.txt +10 -10
  230. package/resources/old/website-image-resource.js +1185 -1185
  231. package/resources/process-js.js +498 -498
  232. package/resources/processors/bundlers/bundle.js +29 -29
  233. package/resources/processors/bundlers/bundler.js +23 -23
  234. package/resources/processors/bundlers/css-bundler.js +234 -234
  235. package/resources/processors/bundlers/js/JS_Bundler.js +51 -51
  236. package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +388 -391
  237. package/resources/processors/bundlers/js/esbuild/Bundler_Using_ESBuild.js +8 -8
  238. package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +188 -188
  239. package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +191 -192
  240. package/resources/processors/bundlers/js/esbuild/_Old_CSS_Extractor.js +239 -239
  241. package/resources/processors/bundlers/js-bundler.js +263 -263
  242. package/resources/processors/bundlers/test_ast.js +73 -73
  243. package/resources/processors/bundlers/webpage-bundler.js +404 -404
  244. package/resources/processors/bundlers/website-bundler.js +22 -22
  245. package/resources/processors/extractors/Extractor.js +9 -11
  246. package/resources/processors/extractors/js/css_and_js/AST_Node/CSS_And_JS_From_JS_String_Using_AST_Node_Extractor.js +239 -254
  247. package/resources/processors/extractors/js/css_and_js/CSS_And_JS_From_JS_String_Extractor.js +3 -3
  248. package/resources/processors/extractors/string/Pos_Span_String_Extractor.js +93 -93
  249. package/resources/server-installed-tools.js +28 -28
  250. package/resources/server-resource-pool.js +41 -41
  251. package/resources/website-audio-resource.js +735 -735
  252. package/resources/website-css-resource.js +411 -411
  253. package/resources/website-image-resource.js +412 -412
  254. package/resources/website-javascript-resource-processor.js +908 -908
  255. package/resources/website-javascript-resource.js +874 -874
  256. package/resources/website-resource-processor.js +10 -10
  257. package/resources/website-resource.js +164 -164
  258. package/resources/website-static-html-resource.js +199 -199
  259. package/resources/website-template-html-resource.js +231 -231
  260. package/roadmap.md +75 -75
  261. package/server.js +609 -573
  262. package/static-page-context.js +13 -13
  263. package/website/webpage.js +81 -81
  264. package/website/website-group.js +15 -15
  265. package/website/website.js +260 -260
  266. package/examples/controls/11d) window, shared model mirrored integer text fields/both.js +0 -17
  267. package/examples/controls/13) window, shared model mirrored lat_long/client.js +0 -933
  268. package/examples/controls/13) window, shared model mirrored lat_long/server.js +0 -50
  269. package/examples/controls/14) window, control compositional model/client.js +0 -328
  270. package/examples/controls/14) window, control compositional model/server.js +0 -118
  271. package/examples/controls/14a) window, control spec has compositional model/client.js +0 -440
  272. package/examples/controls/14a) window, control spec has compositional model/server.js +0 -118
  273. package/examples/controls/15) window, text field/client.js +0 -256
  274. package/examples/controls/16) Window([Text_Input])/client.js +0 -266
  275. package/examples/controls/16) Window([Text_Input])/server.js +0 -109
  276. package/examples/controls/16a) Window([Text_Input]) Integer data.model.data_type/client.js +0 -494
  277. package/examples/controls/16a) Window([Text_Input]) Integer data.model.data_type/isomorphic.js +0 -24
  278. package/examples/controls/16a) Window([Text_Input]) Integer data.model.data_type/server.js +0 -73
  279. package/examples/controls/2b) two window, context menus/client.js +0 -193
  280. package/examples/controls/2b) two window, context menus/server.js +0 -114
  281. package/examples/controls/4a) window, tabbed panel with various controls inside/client.js +0 -233
  282. package/examples/controls/4a) window, tabbed panel with various controls inside/server.js +0 -118
@@ -1,735 +1,735 @@
1
-
2
- // Need to maintain the various concepts applying here.
3
- // Get them working or throwing errors / set to NYI if they are not so simple to fix / implement.
4
-
5
- /*
6
- if (typeof define !== 'function') {
7
- var define = require('amdefine')(module);
8
- }
9
-
10
- // I would like my own (fast) way of reading MP3 metadata.
11
-
12
- // Had a problem seeking later parts of the track in Chrome. It would request a few seconds too little audio from the server.
13
- // Seems like Chrome estimated positions for VBR audio are out.
14
- // This bay be improved by changing to a constant bitrate (though that is less efficient encoding, generally)
15
-
16
- // Other parts of the system are likely to be more important.
17
- // It may be useful to have an interface to administer the site's audio.
18
-
19
- // Browse tracks, and encode them into different bit rates and formats.
20
- // Maintain copies of the tracks in different bit rates and formats.
21
-
22
-
23
- define(['module', 'path', 'fs', 'url', '../../web/jsgui-html', 'os', 'http', 'url', './resource',
24
- '../../web/jsgui-je-suis-xml', 'cookies', '../../fs/jsgui-node-fs2-core', '../../audio/jsgui-node-audio-metadata', 'crypto'],
25
-
26
- function(module, path, fs, url, jsgui, os, http, libUrl,
27
- Resource, JeSuisXML, Cookies, fs2, audio_metadata, crypto) {
28
- */
29
-
30
- const path = require('path'), fs = require('fs'), url = require('url'), jsgui = require('../../web/jsgui-html'), os = require('os'), http = require('http'), libUrl = require('url'),
31
- Resource = require('./resource'), Cookies = require('./cookies'), fs2 = require('../../fs/jsgui-node-fs2-core'), audio_metadata = require('../../audio/jsgui-node-audio-metadata'), crypto = require('crypto');
32
-
33
-
34
- var stringify = jsgui.stringify, each = jsgui.eac, arrayify = jsgui.arrayify, tof = jsgui.tof;
35
- var filter_map_by_regex = jsgui.filter_map_by_regex;
36
- var Class = jsgui.Class, Data_Object = jsgui.Data_Object, Enhanced_Data_Object = jsgui.Enhanced_Data_Object;
37
- var fp = jsgui.fp, is_defined = jsgui.is_defined;
38
- var Collection = jsgui.Collection;
39
-
40
- // This resource may have quite a lot of functionality put in to deal with
41
- // seriving images in an optimized way.
42
- // Want this so it also serves the developer in that images can be put in place
43
- // and modified easily in an unoptimized way. Then they get put in place in an
44
- // optimized way on request or automatically. Want to incorporate sprite sheet generation
45
- // here. This should handle requests for individual images, but it's also possible sprites
46
- // could be requested. If that's the case, maybe it should pass it onto a sprite resource.
47
- // It would be really good to have practically instant sprite generation, using C / C++
48
- // and maybe OpenCL.
49
- // It could be requests to a sprite resource that returns a predefined selection of
50
- // assets.
51
- // The image resource may also be called upon to return rescaled versions.
52
- // That's something that OpenCL would also be very fast at.
53
- // The image / spritesheet resources may be connected to other database resources that provide
54
- // caching and indexing of images.
55
- // These would most likely be abstractions over data resources.
56
-
57
- // Want to make an image interface to a flexible db interface.
58
- // Serving and caching optimized images would be cool.
59
-
60
- // Rather than relying on storing image versions in a DB (which would be cool, esp for distributed)
61
- // we can store image versions + spritesheets on the local disk.
62
- // Cache them in RAM as well.
63
- // Storing them in GPU RAM would be very cool, especially if from there we can get versions with
64
- // different operations done, or the output of operations.
65
-
66
-
67
- // May need to change around a fair few references to make it workable.
68
- // May need some more complicated logic to change it to the path for service.
69
-
70
-
71
- // need to see what type of image it is.
72
- var mime_types = {
73
- 'acc': 'audio/acc',
74
- 'mp4': 'audio/mp4',
75
- 'mp3': 'audio/mpeg3',
76
- 'mpeg': 'audio/mpeg',
77
- 'ogg': 'audio/ogg',
78
- 'wav': 'audio/wav',
79
- 'webm': 'audio/webm'
80
- };
81
-
82
- var serve_audio_file_from_disk = fp(function(a, sig) {
83
-
84
- var filePath, start_pos = 0, end_pos, response;
85
- var using_byte_range = false;
86
-
87
- if (a.l == 2) {
88
- filePath = a[0];
89
- response = a[1];
90
-
91
- }
92
- if (a.l == 3) {
93
- filePath = a[0];
94
- start_pos = a[1];
95
- response = a[2];
96
- using_byte_range = true;
97
-
98
- }
99
- if (a.l == 4) {
100
- filePath = a[0];
101
- start_pos = a[1];
102
- end_pos = a[2]
103
- response = a[3];
104
- using_byte_range = true;
105
- }
106
- console.log('serve_audio_file_from_disk filePath ', filePath);
107
-
108
- var extname = path.extname(filePath);
109
- console.log('extname ' + extname);
110
-
111
- var extension = extname.substr(1);
112
- console.log('extension ' + extension);
113
-
114
-
115
- // then return the right MIME type for that extension.
116
-
117
- // No, don't load the image file as a string.
118
-
119
- // fs loadfile
120
- // async, then serve it with the correct mime type, write to the response buffer.
121
-
122
- // can this be streamed to the response buffer?
123
-
124
- //console.log('filePath', filePath);
125
-
126
- // This was served from Express in another app:
127
- /*
128
- Accept-Ranges:bytes
129
- Cache-Control:public, max-age=0
130
- Connection:keep-alive
131
- Content-Length:7831024
132
- Content-Range:bytes 0-7831023/7831024
133
- Content-Type:audio/mpeg
134
- Date:Fri, 02 May 2014 15:41:56 GMT
135
- ETag:"7831024-1357308361000"
136
- Last-Modified:Fri, 04 Jan 2013 14:06:01 GMT
137
- X-Powered-By:Express
138
-
139
- Currently served:
140
-
141
- Accept-Ranges:bytes
142
- Connection:keep-alive
143
- Content-Length:7831024
144
- Content-Range:bytes 0-7831024/7831024
145
- Content-Type:audio/mpeg3
146
- Date:Fri, 02 May 2014 18:01:47 GMT
147
-
148
-
149
- */
150
-
151
- // It seems like this needs to present an etag to the client in order to work successfully.
152
-
153
-
154
-
155
-
156
- // May be better to use fs.read
157
- // Serve this as a stream
158
- // The client may not request it so quickly.
159
- // However, may not want lots of access to the disk, so storing it in RAM while being served may make sense.
160
-
161
-
162
-
163
-
164
- //
165
-
166
- /*
167
-
168
- fs.open('./data/index.html', 'r', function(err, fd) {
169
- if(err) throw err;
170
- var str = new Buffer(3);
171
- fs.read(fd, buf, 0, buf.length, null, function(err, bytesRead, buffer) {
172
- if(err) throw err;
173
- console.log(err, bytesRead, buffer);
174
- fs.close(fd, ChaipaKwa, are you there?
175
- function() {
176
- console.log('Done');
177
- });
178
- });
179
- });
180
-
181
- */
182
-
183
- // This current code is probably more memory efficient.
184
- // A greater efficiency could be gained (possibly) by storing the whole MP3 in memory while it is being served,
185
- // and using the same buffer to send to more than 1 client.
186
-
187
- fs.stat(filePath, function (err, stats) {
188
- if (err) {
189
-
190
- // The file probably was not found.
191
- // Return a 404.
192
-
193
- //response.status(404).send('Not found');
194
-
195
- response.writeHead(404, {
196
-
197
- "Content-Type": "text/plain"
198
-
199
- });
200
-
201
- response.write("404 Not Found\n");
202
-
203
- response.end();
204
-
205
-
206
- //throw err;
207
- } else {
208
- console.log('stats.size', stats.size);
209
-
210
- //var l = stats.size;
211
-
212
- var l;
213
-
214
- var response_code = 200;
215
- //if (start_pos > 0) {
216
- // response_code = 206;
217
- //}
218
-
219
-
220
- if (using_byte_range) {
221
- response_code = 206;
222
- if (start_pos) {
223
- l = stats.size - start_pos ;
224
-
225
- }
226
-
227
-
228
-
229
- var rs_opts = {
230
- 'start': start_pos
231
- };
232
-
233
- if (end_pos) {
234
- rs_opts.end = end_pos + 1;
235
- l = end_pos;
236
- }
237
-
238
- if (start_pos && end_pos) {
239
- l = (end_pos + 1) - start_pos;
240
- }
241
-
242
-
243
- } else {
244
- l = stats.size;
245
- }
246
-
247
-
248
- console.log('rs_opts', rs_opts);
249
- var rs = fs.createReadStream(filePath, rs_opts);
250
-
251
- rs.pause();
252
-
253
- var c = 0;
254
-
255
- // Response code 206 for partial content.
256
- // Need to only do this if the browser is asking for partial content though.
257
-
258
- // It seems like partial requests rely on etags.
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
-
267
- // Needs to have a new etag for each file.
268
- // Can use a hash of the file path.
269
-
270
-
271
- var key = 'ready salted';
272
- var hash = crypto.createHmac('sha1', key).update(filePath).digest('hex');
273
-
274
- // Get last modified time from file.
275
-
276
-
277
- // Need to handle 0-n ranges
278
- // iOS starts the audio download with a 0-1 range.
279
-
280
- // Seems that with the range request we should return 1 more byte.
281
-
282
-
283
-
284
- // Don't necessarily do content-range.
285
-
286
- var o_head = {'Content-Type': mime_types[extension],
287
- //'Accept-Ranges': 'bytes',
288
-
289
- 'ETag': hash,
290
- //'Last-Modified': 'Fri, 04 Jan 2013 14:06:01 GMT',
291
- 'Last-Modified': stats.mtime,
292
-
293
- 'Content-Length': l//,
294
-
295
- // Not serving the whole content (fill amount - 1) gets the 206 response to work.
296
- //'Content-Range': 'bytes ' + start_pos + '-' + (stats.size - 1) + '/' + stats.size
297
- };
298
-
299
- if (using_byte_range) {
300
- o_head['Accept-Ranges'] = 'bytes';
301
- start_pos = start_pos || 0;
302
-
303
- if (end_pos) {
304
- o_head['Content-Range'] = 'bytes ' + start_pos + '-' + (end_pos) + '/' + stats.size
305
- } else {
306
- o_head['Content-Range'] = 'bytes ' + start_pos + '-' + (stats.size - 1) + '/' + stats.size
307
- }
308
-
309
-
310
- }
311
-
312
- console.log('o_head', o_head);
313
-
314
-
315
- response.writeHead(response_code, o_head);
316
-
317
- //response.pipe()
318
-
319
- rs.pipe(response);
320
-
321
-
322
-
323
- //rs.on('data', function(chunk) {
324
- //c = c + chunk.length;
325
- //console.log('got %d bytes of data', chunk.length);
326
- //console.log('bytes read so far', c);
327
- //});
328
- rs.resume();
329
-
330
-
331
-
332
-
333
-
334
-
335
- /*
336
- fs.open(filePath, 'r', function(err, fd) {
337
- if (err) {
338
- throw err;
339
- } else {
340
- // Do we know how long the file is?
341
- // We need to get the metadata first?
342
-
343
- // Want to stream the file, sequentially.
344
-
345
-
346
-
347
-
348
- }
349
- })
350
- */
351
-
352
- }
353
-
354
- });
355
-
356
-
357
-
358
- /*
359
-
360
- fs.readFile(filePath, function(err, data) {
361
- if (err) {
362
- throw err;
363
- } else {
364
- console.log('cb readfile');
365
- response.writeHead(200, {'Content-Type': mime_types[extension],
366
- 'Accept-Ranges': 'bytes',
367
- 'Content-Length': data.length,
368
- 'Content-Range': 'bytes 0-' + data.length + '/' + data.length
369
- });
370
-
371
- // Accept-Ranges:bytes
372
- response.end(data, 'binary');
373
-
374
- }
375
- });
376
- */
377
-
378
-
379
- //fs2.load_file_as_string(filePath, function (err, data) {
380
- // if (err) {
381
- // throw err;
382
- // } else {
383
- // //var servableJs = updateReferencesForServing(data);
384
- // response.writeHead(200, {'Content-Type': mime_types[extension]});
385
- // response.end(data);
386
- // }
387
- //});
388
- });
389
-
390
-
391
- var Site_Audio = Resource.extend({
392
-
393
-
394
- 'init': function(spec) {
395
- super(spec);
396
- //this._super(spec);
397
-
398
- this.meta.set('custom_paths', new Data_Object({}));
399
- // Those are custom file paths.
400
-
401
- // could have a collection of directories, indexed by name, that get served.
402
-
403
- // Index the collection by string value?
404
- this.meta.set('served_directories', new Collection({'index_by': 'name'}));
405
- },
406
- 'start': function(callback) {
407
- // Load the tracks and find out their lengths.
408
-
409
- console.log('Site Audio Resource Start');
410
-
411
- var meta = this.meta;
412
- var albums = meta.get('albums');
413
-
414
- if (albums) {
415
- each(albums, function(album) {
416
- // We load the track length.
417
-
418
- var tracks = album.tracks;
419
-
420
- var l = tracks.length;
421
-
422
- each(tracks, function(track, i_track) {
423
- var track_base_name = (i_track + 1).toString();
424
- if (track_base_name.length == 1) {
425
- track_base_name = '0' + track_base_name;
426
- }
427
- var track_mp3_path = album.path + '/mp3/' + track_base_name + '.mp3';
428
- //console.log('track_mp3_path', track_mp3_path);
429
- // perhaps using call_multi
430
- // load this up, get the track length
431
- audio_metadata.from_file(track_mp3_path, function(err, metadata) {
432
- if (err) {
433
- throw err;
434
- } else {
435
- //console.log('metadata', metadata);
436
-
437
- var ms_duration = metadata.ms_duration;
438
- track.ms_duration = ms_duration;
439
-
440
- l--;
441
-
442
- if (l == 0) {
443
- //console.log('tracks', tracks);
444
- callback(null, true);
445
- }
446
-
447
- }
448
- })
449
-
450
-
451
- });
452
-
453
-
454
- });
455
-
456
- } else {
457
- callback(null, true);
458
- }
459
-
460
- //console.log('albums', albums);
461
- //console.log('tof(albums)', tof(albums));
462
-
463
-
464
-
465
- },
466
- 'serve_directory': function(path) {
467
- // Serves that directory, as any files given in that directory can be served from /js
468
- var served_directories = this.meta.get('served_directories');
469
- //console.log('served_directories ' + stringify(served_directories));
470
- //served_directories.push(path);
471
- served_directories.push({
472
- 'name': path
473
- });
474
- //console.log('served_directories ' + stringify(served_directories));
475
- //console.log('path ' + path);
476
-
477
-
478
- //throw 'stop';
479
-
480
-
481
-
482
- },
483
-
484
- // basically get requests, but can handle more than just get.
485
- 'process': function(req, res) {
486
- console.log('Site_JavaScript processing');
487
- var remoteAddress = req.connection.remoteAddress;
488
-
489
- var custom_paths = this.meta.get('custom_paths');
490
-
491
- var rurl = req.url;
492
-
493
- var pool = this.meta.get('pool');
494
- // should have a bunch of resources from the pool.
495
-
496
- //var pool_resources = pool.resources();
497
- //console.log('pool_resources ' + stringify(pool_resources));
498
-
499
- //console.log('req', req);
500
-
501
- var headers = req.headers;
502
- console.log('headers', headers);
503
-
504
- // bytes=6723861-
505
-
506
- var range = headers.range;
507
- console.log('range', range);
508
-
509
-
510
-
511
- var byte_start_pos;
512
- var byte_end_pos;
513
-
514
- if (range) {
515
- var s_range = range.split('=');
516
-
517
- console.log('s_range', s_range);
518
-
519
- var s_range_2 = s_range[1].split('-');
520
-
521
- console.log('s_range_2', s_range_2);
522
-
523
- if (s_range_2[0]) {
524
- byte_start_pos = parseInt(s_range_2[0], 10);
525
- }
526
- if (s_range_2[1]) {
527
- console.log('s_range_2[1]', s_range_2[1]);
528
- byte_end_pos = parseInt(s_range_2[1], 10);
529
- }
530
- }
531
-
532
- console.log('byte_start_pos', byte_start_pos);
533
- console.log('byte_end_pos', byte_end_pos);
534
-
535
- //if (range.substr())
536
-
537
-
538
-
539
-
540
-
541
- // It looks like this will need to handle byte ranges too.
542
-
543
-
544
-
545
-
546
- var wildcard_value = req.params.wildcard_value;
547
- //console.log('wildcard_value', wildcard_value);
548
-
549
- if (wildcard_value) {
550
- var s_path = wildcard_value.split('/');
551
- //console.log('s_path', s_path);
552
-
553
- if (s_path.length == 3) {
554
- var album_url_name = s_path[1];
555
- var track_url_name = s_path[2];
556
-
557
- var s_track_url_name = track_url_name.split('.');
558
- var track_base_name = s_track_url_name[0];
559
- var track_extension = s_track_url_name[1];
560
-
561
- //console.log('track_base_name', track_base_name);
562
- console.log('track_extension', track_extension);
563
-
564
- // Need to match it up with the resource's albums
565
-
566
-
567
-
568
- // Then load up and serve the file.
569
-
570
- //var media_file_path =
571
-
572
- // Likely to have been given specialised path info, in the metadata.
573
- // Could have been provided with an album's path.
574
-
575
- var meta = this.meta;
576
- //console.log('meta', meta);
577
-
578
- var albums = meta.get('albums');
579
- //console.log('albums', albums);
580
-
581
- var parsed_album_url_name = parseInt(album_url_name, 10);
582
- var i_album = parsed_album_url_name - 1;
583
-
584
- var album = albums[i_album];
585
-
586
-
587
- //var tracks = album.get('tracks');
588
- var tracks = album.tracks;
589
-
590
- var i_track = parseInt(track_base_name, 10);
591
-
592
- var s_track = i_track.toString();
593
- if (s_track.length == 1) {
594
- s_track = '0' + s_track;
595
- }
596
-
597
- //console.log('s_track', s_track);
598
-
599
- // Anyway, choose the right file (from mp3 dir for the moment)
600
-
601
- // Must also be able to serve ogg paths.
602
-
603
-
604
-
605
- var media_file_path = album.path + '/' + track_extension + '/' + s_track + '.' + track_extension;
606
- console.log('media_file_path', media_file_path);
607
- //console.log('res (response)', res);
608
-
609
- // Also, we may not want to serve the whole audio file, but to begin the stream.
610
- // Maybe we could keep the whole audio file in memory as a buffer.
611
- // Don't want lots of large temporary buffers.
612
-
613
-
614
-
615
-
616
- // Also need to take into account the byte range.
617
- // The serve audio function could be changed so that it can serve a byterange, eg x-
618
- // from x to the end
619
-
620
- if (byte_end_pos) {
621
- serve_audio_file_from_disk(media_file_path, byte_start_pos, byte_end_pos, res);
622
- } else {
623
-
624
- if (typeof byte_start_pos != 'undefined') {
625
- serve_audio_file_from_disk(media_file_path, byte_start_pos, res);
626
- } else {
627
- serve_audio_file_from_disk(media_file_path, res);
628
- }
629
-
630
-
631
- }
632
-
633
-
634
-
635
-
636
-
637
- //console.log('tracks', tracks);
638
-
639
- //
640
- }
641
- }
642
-
643
- //throw 'stop';
644
-
645
- /*
646
-
647
-
648
-
649
-
650
- var url_parts = url.parse(req.url, true);
651
- //console.log('url_parts ' + stringify(url_parts));
652
- var splitPath = url_parts.path.substr(1).split('/');
653
-
654
- // Want the path inside the resource as well.
655
-
656
- //console.log('resource site css splitPath ' + stringify(splitPath));
657
-
658
-
659
- if (rurl.substr(0, 1) == '/') rurl = rurl.substr(1);
660
- rurl = rurl.replace(/\./g, '☺');
661
- //console.log('rurl ' + rurl);
662
-
663
- var custom_response_entry = custom_paths.get(rurl);
664
- //console.log('custom_response_entry ' + stringify(custom_response_entry));
665
-
666
- // Should probably already be given the audio path, as well as the path within the audio path.
667
-
668
- // Custom audio resource publishers could seem like a decent business.
669
-
670
- if (custom_response_entry) {
671
- var tcr = tof(custom_response_entry);
672
- //console.log('tcr ' + tcr);
673
-
674
- if (tcr == 'data_value') {
675
- val = custom_response_entry.value();
676
- //console.log('val ' + val);
677
-
678
- var tval = tof(val);
679
-
680
- if (tval == 'string') {
681
- // then it should be a local file path, serve it.
682
- serve_image_file_from_disk(val, res);
683
- }
684
- }
685
- } else {
686
- //console.log('splitPath', splitPath);
687
- if (splitPath.length > 0) {
688
-
689
- if (splitPath[0] == 'audio') {
690
-
691
- if (splitPath.length > 1) {
692
- if (splitPath.length == 2) {
693
- var fileName = splitPath[1];
694
- //console.log('url_parts.path ' + url_parts.path);
695
- var filePath = url_parts.path.substr(1);
696
- //console.log('module.uri ' + module.uri);
697
- var val2 = path.dirname(module.uri);
698
- console.log('val2 ' + val2);
699
-
700
- var diskPath = '../../ws/audio/' + fileName;
701
-
702
- serve_image_file_from_disk(diskPath, res);
703
-
704
- } else {
705
- if (splitPath.length > 2) {
706
-
707
- // need to put the rest of it together...
708
-
709
- var fileName = splitPath.slice(1, splitPath.length).join('/');
710
- console.log('fileName', fileName);
711
-
712
-
713
- var filePath = url_parts.path.substr(1);
714
- //console.log('module.uri ' + module.uri);
715
- var val2 = path.dirname(module.uri);
716
- console.log('val2 ' + val2);
717
- var diskPath = '../../ws/audio/' + fileName;
718
-
719
- serve_image_file_from_disk(diskPath, res);
720
-
721
- }
722
-
723
- }
724
- }
725
- }
726
- }
727
- }
728
- */
729
- }
730
- });
731
-
732
- //return Site_Audio;
733
- //});
734
-
735
- module.exports = Site_Audio;
1
+
2
+ // Need to maintain the various concepts applying here.
3
+ // Get them working or throwing errors / set to NYI if they are not so simple to fix / implement.
4
+
5
+ /*
6
+ if (typeof define !== 'function') {
7
+ var define = require('amdefine')(module);
8
+ }
9
+
10
+ // I would like my own (fast) way of reading MP3 metadata.
11
+
12
+ // Had a problem seeking later parts of the track in Chrome. It would request a few seconds too little audio from the server.
13
+ // Seems like Chrome estimated positions for VBR audio are out.
14
+ // This bay be improved by changing to a constant bitrate (though that is less efficient encoding, generally)
15
+
16
+ // Other parts of the system are likely to be more important.
17
+ // It may be useful to have an interface to administer the site's audio.
18
+
19
+ // Browse tracks, and encode them into different bit rates and formats.
20
+ // Maintain copies of the tracks in different bit rates and formats.
21
+
22
+
23
+ define(['module', 'path', 'fs', 'url', '../../web/jsgui-html', 'os', 'http', 'url', './resource',
24
+ '../../web/jsgui-je-suis-xml', 'cookies', '../../fs/jsgui-node-fs2-core', '../../audio/jsgui-node-audio-metadata', 'crypto'],
25
+
26
+ function(module, path, fs, url, jsgui, os, http, libUrl,
27
+ Resource, JeSuisXML, Cookies, fs2, audio_metadata, crypto) {
28
+ */
29
+
30
+ const path = require('path'), fs = require('fs'), url = require('url'), jsgui = require('../../web/jsgui-html'), os = require('os'), http = require('http'), libUrl = require('url'),
31
+ Resource = require('./resource'), Cookies = require('./cookies'), fs2 = require('../../fs/jsgui-node-fs2-core'), audio_metadata = require('../../audio/jsgui-node-audio-metadata'), crypto = require('crypto');
32
+
33
+
34
+ var stringify = jsgui.stringify, each = jsgui.eac, arrayify = jsgui.arrayify, tof = jsgui.tof;
35
+ var filter_map_by_regex = jsgui.filter_map_by_regex;
36
+ var Class = jsgui.Class, Data_Object = jsgui.Data_Object, Enhanced_Data_Object = jsgui.Enhanced_Data_Object;
37
+ var fp = jsgui.fp, is_defined = jsgui.is_defined;
38
+ var Collection = jsgui.Collection;
39
+
40
+ // This resource may have quite a lot of functionality put in to deal with
41
+ // seriving images in an optimized way.
42
+ // Want this so it also serves the developer in that images can be put in place
43
+ // and modified easily in an unoptimized way. Then they get put in place in an
44
+ // optimized way on request or automatically. Want to incorporate sprite sheet generation
45
+ // here. This should handle requests for individual images, but it's also possible sprites
46
+ // could be requested. If that's the case, maybe it should pass it onto a sprite resource.
47
+ // It would be really good to have practically instant sprite generation, using C / C++
48
+ // and maybe OpenCL.
49
+ // It could be requests to a sprite resource that returns a predefined selection of
50
+ // assets.
51
+ // The image resource may also be called upon to return rescaled versions.
52
+ // That's something that OpenCL would also be very fast at.
53
+ // The image / spritesheet resources may be connected to other database resources that provide
54
+ // caching and indexing of images.
55
+ // These would most likely be abstractions over data resources.
56
+
57
+ // Want to make an image interface to a flexible db interface.
58
+ // Serving and caching optimized images would be cool.
59
+
60
+ // Rather than relying on storing image versions in a DB (which would be cool, esp for distributed)
61
+ // we can store image versions + spritesheets on the local disk.
62
+ // Cache them in RAM as well.
63
+ // Storing them in GPU RAM would be very cool, especially if from there we can get versions with
64
+ // different operations done, or the output of operations.
65
+
66
+
67
+ // May need to change around a fair few references to make it workable.
68
+ // May need some more complicated logic to change it to the path for service.
69
+
70
+
71
+ // need to see what type of image it is.
72
+ var mime_types = {
73
+ 'acc': 'audio/acc',
74
+ 'mp4': 'audio/mp4',
75
+ 'mp3': 'audio/mpeg3',
76
+ 'mpeg': 'audio/mpeg',
77
+ 'ogg': 'audio/ogg',
78
+ 'wav': 'audio/wav',
79
+ 'webm': 'audio/webm'
80
+ };
81
+
82
+ var serve_audio_file_from_disk = fp(function(a, sig) {
83
+
84
+ var filePath, start_pos = 0, end_pos, response;
85
+ var using_byte_range = false;
86
+
87
+ if (a.l == 2) {
88
+ filePath = a[0];
89
+ response = a[1];
90
+
91
+ }
92
+ if (a.l == 3) {
93
+ filePath = a[0];
94
+ start_pos = a[1];
95
+ response = a[2];
96
+ using_byte_range = true;
97
+
98
+ }
99
+ if (a.l == 4) {
100
+ filePath = a[0];
101
+ start_pos = a[1];
102
+ end_pos = a[2]
103
+ response = a[3];
104
+ using_byte_range = true;
105
+ }
106
+ console.log('serve_audio_file_from_disk filePath ', filePath);
107
+
108
+ var extname = path.extname(filePath);
109
+ console.log('extname ' + extname);
110
+
111
+ var extension = extname.substr(1);
112
+ console.log('extension ' + extension);
113
+
114
+
115
+ // then return the right MIME type for that extension.
116
+
117
+ // No, don't load the image file as a string.
118
+
119
+ // fs loadfile
120
+ // async, then serve it with the correct mime type, write to the response buffer.
121
+
122
+ // can this be streamed to the response buffer?
123
+
124
+ //console.log('filePath', filePath);
125
+
126
+ // This was served from Express in another app:
127
+ /*
128
+ Accept-Ranges:bytes
129
+ Cache-Control:public, max-age=0
130
+ Connection:keep-alive
131
+ Content-Length:7831024
132
+ Content-Range:bytes 0-7831023/7831024
133
+ Content-Type:audio/mpeg
134
+ Date:Fri, 02 May 2014 15:41:56 GMT
135
+ ETag:"7831024-1357308361000"
136
+ Last-Modified:Fri, 04 Jan 2013 14:06:01 GMT
137
+ X-Powered-By:Express
138
+
139
+ Currently served:
140
+
141
+ Accept-Ranges:bytes
142
+ Connection:keep-alive
143
+ Content-Length:7831024
144
+ Content-Range:bytes 0-7831024/7831024
145
+ Content-Type:audio/mpeg3
146
+ Date:Fri, 02 May 2014 18:01:47 GMT
147
+
148
+
149
+ */
150
+
151
+ // It seems like this needs to present an etag to the client in order to work successfully.
152
+
153
+
154
+
155
+
156
+ // May be better to use fs.read
157
+ // Serve this as a stream
158
+ // The client may not request it so quickly.
159
+ // However, may not want lots of access to the disk, so storing it in RAM while being served may make sense.
160
+
161
+
162
+
163
+
164
+ //
165
+
166
+ /*
167
+
168
+ fs.open('./data/index.html', 'r', function(err, fd) {
169
+ if(err) throw err;
170
+ var str = new Buffer(3);
171
+ fs.read(fd, buf, 0, buf.length, null, function(err, bytesRead, buffer) {
172
+ if(err) throw err;
173
+ console.log(err, bytesRead, buffer);
174
+ fs.close(fd, ChaipaKwa, are you there?
175
+ function() {
176
+ console.log('Done');
177
+ });
178
+ });
179
+ });
180
+
181
+ */
182
+
183
+ // This current code is probably more memory efficient.
184
+ // A greater efficiency could be gained (possibly) by storing the whole MP3 in memory while it is being served,
185
+ // and using the same buffer to send to more than 1 client.
186
+
187
+ fs.stat(filePath, function (err, stats) {
188
+ if (err) {
189
+
190
+ // The file probably was not found.
191
+ // Return a 404.
192
+
193
+ //response.status(404).send('Not found');
194
+
195
+ response.writeHead(404, {
196
+
197
+ "Content-Type": "text/plain"
198
+
199
+ });
200
+
201
+ response.write("404 Not Found\n");
202
+
203
+ response.end();
204
+
205
+
206
+ //throw err;
207
+ } else {
208
+ console.log('stats.size', stats.size);
209
+
210
+ //var l = stats.size;
211
+
212
+ var l;
213
+
214
+ var response_code = 200;
215
+ //if (start_pos > 0) {
216
+ // response_code = 206;
217
+ //}
218
+
219
+
220
+ if (using_byte_range) {
221
+ response_code = 206;
222
+ if (start_pos) {
223
+ l = stats.size - start_pos ;
224
+
225
+ }
226
+
227
+
228
+
229
+ var rs_opts = {
230
+ 'start': start_pos
231
+ };
232
+
233
+ if (end_pos) {
234
+ rs_opts.end = end_pos + 1;
235
+ l = end_pos;
236
+ }
237
+
238
+ if (start_pos && end_pos) {
239
+ l = (end_pos + 1) - start_pos;
240
+ }
241
+
242
+
243
+ } else {
244
+ l = stats.size;
245
+ }
246
+
247
+
248
+ console.log('rs_opts', rs_opts);
249
+ var rs = fs.createReadStream(filePath, rs_opts);
250
+
251
+ rs.pause();
252
+
253
+ var c = 0;
254
+
255
+ // Response code 206 for partial content.
256
+ // Need to only do this if the browser is asking for partial content though.
257
+
258
+ // It seems like partial requests rely on etags.
259
+
260
+
261
+
262
+
263
+
264
+
265
+
266
+
267
+ // Needs to have a new etag for each file.
268
+ // Can use a hash of the file path.
269
+
270
+
271
+ var key = 'ready salted';
272
+ var hash = crypto.createHmac('sha1', key).update(filePath).digest('hex');
273
+
274
+ // Get last modified time from file.
275
+
276
+
277
+ // Need to handle 0-n ranges
278
+ // iOS starts the audio download with a 0-1 range.
279
+
280
+ // Seems that with the range request we should return 1 more byte.
281
+
282
+
283
+
284
+ // Don't necessarily do content-range.
285
+
286
+ var o_head = {'Content-Type': mime_types[extension],
287
+ //'Accept-Ranges': 'bytes',
288
+
289
+ 'ETag': hash,
290
+ //'Last-Modified': 'Fri, 04 Jan 2013 14:06:01 GMT',
291
+ 'Last-Modified': stats.mtime,
292
+
293
+ 'Content-Length': l//,
294
+
295
+ // Not serving the whole content (fill amount - 1) gets the 206 response to work.
296
+ //'Content-Range': 'bytes ' + start_pos + '-' + (stats.size - 1) + '/' + stats.size
297
+ };
298
+
299
+ if (using_byte_range) {
300
+ o_head['Accept-Ranges'] = 'bytes';
301
+ start_pos = start_pos || 0;
302
+
303
+ if (end_pos) {
304
+ o_head['Content-Range'] = 'bytes ' + start_pos + '-' + (end_pos) + '/' + stats.size
305
+ } else {
306
+ o_head['Content-Range'] = 'bytes ' + start_pos + '-' + (stats.size - 1) + '/' + stats.size
307
+ }
308
+
309
+
310
+ }
311
+
312
+ console.log('o_head', o_head);
313
+
314
+
315
+ response.writeHead(response_code, o_head);
316
+
317
+ //response.pipe()
318
+
319
+ rs.pipe(response);
320
+
321
+
322
+
323
+ //rs.on('data', function(chunk) {
324
+ //c = c + chunk.length;
325
+ //console.log('got %d bytes of data', chunk.length);
326
+ //console.log('bytes read so far', c);
327
+ //});
328
+ rs.resume();
329
+
330
+
331
+
332
+
333
+
334
+
335
+ /*
336
+ fs.open(filePath, 'r', function(err, fd) {
337
+ if (err) {
338
+ throw err;
339
+ } else {
340
+ // Do we know how long the file is?
341
+ // We need to get the metadata first?
342
+
343
+ // Want to stream the file, sequentially.
344
+
345
+
346
+
347
+
348
+ }
349
+ })
350
+ */
351
+
352
+ }
353
+
354
+ });
355
+
356
+
357
+
358
+ /*
359
+
360
+ fs.readFile(filePath, function(err, data) {
361
+ if (err) {
362
+ throw err;
363
+ } else {
364
+ console.log('cb readfile');
365
+ response.writeHead(200, {'Content-Type': mime_types[extension],
366
+ 'Accept-Ranges': 'bytes',
367
+ 'Content-Length': data.length,
368
+ 'Content-Range': 'bytes 0-' + data.length + '/' + data.length
369
+ });
370
+
371
+ // Accept-Ranges:bytes
372
+ response.end(data, 'binary');
373
+
374
+ }
375
+ });
376
+ */
377
+
378
+
379
+ //fs2.load_file_as_string(filePath, function (err, data) {
380
+ // if (err) {
381
+ // throw err;
382
+ // } else {
383
+ // //var servableJs = updateReferencesForServing(data);
384
+ // response.writeHead(200, {'Content-Type': mime_types[extension]});
385
+ // response.end(data);
386
+ // }
387
+ //});
388
+ });
389
+
390
+
391
+ var Site_Audio = Resource.extend({
392
+
393
+
394
+ 'init': function(spec) {
395
+ super(spec);
396
+ //this._super(spec);
397
+
398
+ this.meta.set('custom_paths', new Data_Object({}));
399
+ // Those are custom file paths.
400
+
401
+ // could have a collection of directories, indexed by name, that get served.
402
+
403
+ // Index the collection by string value?
404
+ this.meta.set('served_directories', new Collection({'index_by': 'name'}));
405
+ },
406
+ 'start': function(callback) {
407
+ // Load the tracks and find out their lengths.
408
+
409
+ console.log('Site Audio Resource Start');
410
+
411
+ var meta = this.meta;
412
+ var albums = meta.get('albums');
413
+
414
+ if (albums) {
415
+ each(albums, function(album) {
416
+ // We load the track length.
417
+
418
+ var tracks = album.tracks;
419
+
420
+ var l = tracks.length;
421
+
422
+ each(tracks, function(track, i_track) {
423
+ var track_base_name = (i_track + 1).toString();
424
+ if (track_base_name.length == 1) {
425
+ track_base_name = '0' + track_base_name;
426
+ }
427
+ var track_mp3_path = album.path + '/mp3/' + track_base_name + '.mp3';
428
+ //console.log('track_mp3_path', track_mp3_path);
429
+ // perhaps using call_multi
430
+ // load this up, get the track length
431
+ audio_metadata.from_file(track_mp3_path, function(err, metadata) {
432
+ if (err) {
433
+ throw err;
434
+ } else {
435
+ //console.log('metadata', metadata);
436
+
437
+ var ms_duration = metadata.ms_duration;
438
+ track.ms_duration = ms_duration;
439
+
440
+ l--;
441
+
442
+ if (l == 0) {
443
+ //console.log('tracks', tracks);
444
+ callback(null, true);
445
+ }
446
+
447
+ }
448
+ })
449
+
450
+
451
+ });
452
+
453
+
454
+ });
455
+
456
+ } else {
457
+ callback(null, true);
458
+ }
459
+
460
+ //console.log('albums', albums);
461
+ //console.log('tof(albums)', tof(albums));
462
+
463
+
464
+
465
+ },
466
+ 'serve_directory': function(path) {
467
+ // Serves that directory, as any files given in that directory can be served from /js
468
+ var served_directories = this.meta.get('served_directories');
469
+ //console.log('served_directories ' + stringify(served_directories));
470
+ //served_directories.push(path);
471
+ served_directories.push({
472
+ 'name': path
473
+ });
474
+ //console.log('served_directories ' + stringify(served_directories));
475
+ //console.log('path ' + path);
476
+
477
+
478
+ //throw 'stop';
479
+
480
+
481
+
482
+ },
483
+
484
+ // basically get requests, but can handle more than just get.
485
+ 'process': function(req, res) {
486
+ console.log('Site_JavaScript processing');
487
+ var remoteAddress = req.connection.remoteAddress;
488
+
489
+ var custom_paths = this.meta.get('custom_paths');
490
+
491
+ var rurl = req.url;
492
+
493
+ var pool = this.meta.get('pool');
494
+ // should have a bunch of resources from the pool.
495
+
496
+ //var pool_resources = pool.resources();
497
+ //console.log('pool_resources ' + stringify(pool_resources));
498
+
499
+ //console.log('req', req);
500
+
501
+ var headers = req.headers;
502
+ console.log('headers', headers);
503
+
504
+ // bytes=6723861-
505
+
506
+ var range = headers.range;
507
+ console.log('range', range);
508
+
509
+
510
+
511
+ var byte_start_pos;
512
+ var byte_end_pos;
513
+
514
+ if (range) {
515
+ var s_range = range.split('=');
516
+
517
+ console.log('s_range', s_range);
518
+
519
+ var s_range_2 = s_range[1].split('-');
520
+
521
+ console.log('s_range_2', s_range_2);
522
+
523
+ if (s_range_2[0]) {
524
+ byte_start_pos = parseInt(s_range_2[0], 10);
525
+ }
526
+ if (s_range_2[1]) {
527
+ console.log('s_range_2[1]', s_range_2[1]);
528
+ byte_end_pos = parseInt(s_range_2[1], 10);
529
+ }
530
+ }
531
+
532
+ console.log('byte_start_pos', byte_start_pos);
533
+ console.log('byte_end_pos', byte_end_pos);
534
+
535
+ //if (range.substr())
536
+
537
+
538
+
539
+
540
+
541
+ // It looks like this will need to handle byte ranges too.
542
+
543
+
544
+
545
+
546
+ var wildcard_value = req.params.wildcard_value;
547
+ //console.log('wildcard_value', wildcard_value);
548
+
549
+ if (wildcard_value) {
550
+ var s_path = wildcard_value.split('/');
551
+ //console.log('s_path', s_path);
552
+
553
+ if (s_path.length == 3) {
554
+ var album_url_name = s_path[1];
555
+ var track_url_name = s_path[2];
556
+
557
+ var s_track_url_name = track_url_name.split('.');
558
+ var track_base_name = s_track_url_name[0];
559
+ var track_extension = s_track_url_name[1];
560
+
561
+ //console.log('track_base_name', track_base_name);
562
+ console.log('track_extension', track_extension);
563
+
564
+ // Need to match it up with the resource's albums
565
+
566
+
567
+
568
+ // Then load up and serve the file.
569
+
570
+ //var media_file_path =
571
+
572
+ // Likely to have been given specialised path info, in the metadata.
573
+ // Could have been provided with an album's path.
574
+
575
+ var meta = this.meta;
576
+ //console.log('meta', meta);
577
+
578
+ var albums = meta.get('albums');
579
+ //console.log('albums', albums);
580
+
581
+ var parsed_album_url_name = parseInt(album_url_name, 10);
582
+ var i_album = parsed_album_url_name - 1;
583
+
584
+ var album = albums[i_album];
585
+
586
+
587
+ //var tracks = album.get('tracks');
588
+ var tracks = album.tracks;
589
+
590
+ var i_track = parseInt(track_base_name, 10);
591
+
592
+ var s_track = i_track.toString();
593
+ if (s_track.length == 1) {
594
+ s_track = '0' + s_track;
595
+ }
596
+
597
+ //console.log('s_track', s_track);
598
+
599
+ // Anyway, choose the right file (from mp3 dir for the moment)
600
+
601
+ // Must also be able to serve ogg paths.
602
+
603
+
604
+
605
+ var media_file_path = album.path + '/' + track_extension + '/' + s_track + '.' + track_extension;
606
+ console.log('media_file_path', media_file_path);
607
+ //console.log('res (response)', res);
608
+
609
+ // Also, we may not want to serve the whole audio file, but to begin the stream.
610
+ // Maybe we could keep the whole audio file in memory as a buffer.
611
+ // Don't want lots of large temporary buffers.
612
+
613
+
614
+
615
+
616
+ // Also need to take into account the byte range.
617
+ // The serve audio function could be changed so that it can serve a byterange, eg x-
618
+ // from x to the end
619
+
620
+ if (byte_end_pos) {
621
+ serve_audio_file_from_disk(media_file_path, byte_start_pos, byte_end_pos, res);
622
+ } else {
623
+
624
+ if (typeof byte_start_pos != 'undefined') {
625
+ serve_audio_file_from_disk(media_file_path, byte_start_pos, res);
626
+ } else {
627
+ serve_audio_file_from_disk(media_file_path, res);
628
+ }
629
+
630
+
631
+ }
632
+
633
+
634
+
635
+
636
+
637
+ //console.log('tracks', tracks);
638
+
639
+ //
640
+ }
641
+ }
642
+
643
+ //throw 'stop';
644
+
645
+ /*
646
+
647
+
648
+
649
+
650
+ var url_parts = url.parse(req.url, true);
651
+ //console.log('url_parts ' + stringify(url_parts));
652
+ var splitPath = url_parts.path.substr(1).split('/');
653
+
654
+ // Want the path inside the resource as well.
655
+
656
+ //console.log('resource site css splitPath ' + stringify(splitPath));
657
+
658
+
659
+ if (rurl.substr(0, 1) == '/') rurl = rurl.substr(1);
660
+ rurl = rurl.replace(/\./g, '☺');
661
+ //console.log('rurl ' + rurl);
662
+
663
+ var custom_response_entry = custom_paths.get(rurl);
664
+ //console.log('custom_response_entry ' + stringify(custom_response_entry));
665
+
666
+ // Should probably already be given the audio path, as well as the path within the audio path.
667
+
668
+ // Custom audio resource publishers could seem like a decent business.
669
+
670
+ if (custom_response_entry) {
671
+ var tcr = tof(custom_response_entry);
672
+ //console.log('tcr ' + tcr);
673
+
674
+ if (tcr == 'data_value') {
675
+ val = custom_response_entry.value();
676
+ //console.log('val ' + val);
677
+
678
+ var tval = tof(val);
679
+
680
+ if (tval == 'string') {
681
+ // then it should be a local file path, serve it.
682
+ serve_image_file_from_disk(val, res);
683
+ }
684
+ }
685
+ } else {
686
+ //console.log('splitPath', splitPath);
687
+ if (splitPath.length > 0) {
688
+
689
+ if (splitPath[0] == 'audio') {
690
+
691
+ if (splitPath.length > 1) {
692
+ if (splitPath.length == 2) {
693
+ var fileName = splitPath[1];
694
+ //console.log('url_parts.path ' + url_parts.path);
695
+ var filePath = url_parts.path.substr(1);
696
+ //console.log('module.uri ' + module.uri);
697
+ var val2 = path.dirname(module.uri);
698
+ console.log('val2 ' + val2);
699
+
700
+ var diskPath = '../../ws/audio/' + fileName;
701
+
702
+ serve_image_file_from_disk(diskPath, res);
703
+
704
+ } else {
705
+ if (splitPath.length > 2) {
706
+
707
+ // need to put the rest of it together...
708
+
709
+ var fileName = splitPath.slice(1, splitPath.length).join('/');
710
+ console.log('fileName', fileName);
711
+
712
+
713
+ var filePath = url_parts.path.substr(1);
714
+ //console.log('module.uri ' + module.uri);
715
+ var val2 = path.dirname(module.uri);
716
+ console.log('val2 ' + val2);
717
+ var diskPath = '../../ws/audio/' + fileName;
718
+
719
+ serve_image_file_from_disk(diskPath, res);
720
+
721
+ }
722
+
723
+ }
724
+ }
725
+ }
726
+ }
727
+ }
728
+ */
729
+ }
730
+ });
731
+
732
+ //return Site_Audio;
733
+ //});
734
+
735
+ module.exports = Site_Audio;