Class: Epuber::Server
- Inherits:
-
Sinatra::Base
- Object
- Sinatra::Base
- Epuber::Server
- Defined in:
- lib/epuber/server.rb,
lib/epuber/server/handlers.rb
Overview
API:
- LATER
-
/file/<path-or-pattern> – displays pretty file (image, text file) (for example: /file/text/s01.xhtml or /file/text/s01.bade)
Defined Under Namespace
Classes: ShowExceptions
Helpers collapse
- ._compile_book ⇒ Object
- .changes_detected(_modified, _added, _removed) ⇒ Object
- .compile_book(&completion) ⇒ Object
- .filter_not_project_files(files_paths) ⇒ Array<String>
- .notify_clients(type, data = nil) ⇒ Object
- .relative_path_to_book_file(path) ⇒ String
- .reload_bookspec ⇒ Object
- .send_to_clients(message) ⇒ Object
- #add_auto_refresh_script(html_doc) ⇒ Object
- #add_file_to_head(type, html_doc, file_path) ⇒ Object
- #add_keyboard_control_script(html_doc, previous_path, next_path) ⇒ Object
- #add_meta_to_head(name, content, html_doc, force: false) ⇒ Object
- #add_script_file_to_head(html_doc, file_name, *args) ⇒ Object
- #add_script_to_head(html_doc, script_text) ⇒ Object
-
#find_file(pattern = params[:splat].first, source_path: build_path) ⇒ String
Path to file.
- #handle_file(file_path) ⇒ Object
- #handle_websocket(path) ⇒ Object
- #spine_file_at(index) ⇒ Epuber::Book::File?
Class Method Summary collapse
-
._log(level, message) ⇒ Object
Nil.
-
.build_path ⇒ String
Base path.
- .instance_class_accessor(name) ⇒ Object
- .render_bade(file_path) ⇒ String
-
.run!(book, target, verbose: false) ⇒ Object
Nil.
- .sockets ⇒ Object
- .start_listening_if_needed ⇒ Object
- .verbose=(verbose) ⇒ Object
Instance Method Summary collapse
- #_log(level, message) ⇒ Object
- #book ⇒ Epuber::Book::Book
-
#build_path ⇒ String
Base path.
- #file_resolver ⇒ Epuber::Compiler::FileResolver
- #handle_bade(file_path) ⇒ (Fixnum, String)
- #handle_server_bade(file_name) ⇒ (Fixnum, String)
- #handle_xhtml_file(file_path) ⇒ (Fixnum, String)
-
#initialize ⇒ Server
constructor
A new instance of Server.
- #listener ⇒ Listener
- #sockets ⇒ Array<SinatraWebsocket::Connection>
- #spine ⇒ Array<Epuber::Compiler::File>
- #target ⇒ Epuber::Book::Target
- #verbose ⇒ FalseClass, TrueClass
Constructor Details
#initialize ⇒ Server
Returns a new instance of Server.
147 148 149 150 151 152 |
# File 'lib/epuber/server.rb', line 147 def initialize super _log :ui, 'Init compile' self.class.compile_book end |
Class Method Details
._compile_book ⇒ Object
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
# File 'lib/epuber/server.rb', line 345 def self._compile_book begin compiler = Epuber::Compiler.new(book, target) compiler.compile(build_path) self.file_resolver = compiler.file_resolver true rescue => e self.file_resolver = compiler.file_resolver Epuber::UI.error("Compile error: #{e}", location: e) false end end |
._log(level, message) ⇒ Object
Returns nil.
192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/epuber/server.rb', line 192 def self._log(level, ) case level when :ui puts when :info puts "INFO: #{}" if verbose when :get puts " GET: #{}" if verbose when :ws puts " WS: #{}" if verbose else raise "Unknown log level #{level}" end end |
.build_path ⇒ String
Returns base path.
176 177 178 |
# File 'lib/epuber/server.rb', line 176 def self.build_path Epuber::Config.instance.build_path(target) end |
.changes_detected(_modified, _added, _removed) ⇒ Object
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
# File 'lib/epuber/server.rb', line 413 def self.changes_detected(_modified, _added, _removed) all_changed = (_modified + _added + _removed).uniq.map { |path| path.unicode_normalize } reload_bookspec if all_changed.any? { |file| file == book.file_path } changed = filter_not_project_files(all_changed) || [] return if changed.count == 0 notify_clients(:compile_start) _log :ui, "#{Time.now} Compiling" compile_book do |success| unless success _log :ui, 'Skipping other steps' notify_clients(:compile_end) next end _log :ui, 'Notifying clients' # transform all paths to relatives to the server changed.map! do |file| relative = relative_path_to_book_file(file) File.join('', 'book', relative) unless relative.nil? end # remove nil paths (for example bookspec can't be found so the relative path is nil) changed.compact! # if changed.size > 0 && changed.all? { |file| file.end_with?(*Epuber::Compiler::FileFinders::GROUP_EXTENSIONS[:style]) } # notify_clients(:styles, changed) # else notify_clients(:reload, changed) # end end end |
.compile_book(&completion) ⇒ Object
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/epuber/server.rb', line 361 def self.compile_book(&completion) if !@compilation_thread.nil? && @compilation_thread.status != false @compilation_thread.kill @compilation_thread = nil end @compilation_thread = Thread.new do result = _compile_book completion.call(result) unless completion.nil? end if completion.nil? @compilation_thread.join end end |
.filter_not_project_files(files_paths) ⇒ Array<String>
403 404 405 406 407 |
# File 'lib/epuber/server.rb', line 403 def self.filter_not_project_files(files_paths) return nil if file_resolver.nil? files_paths.select { |file| file_resolver.file_with_source_path(file) || book.file_path == file } end |
.instance_class_accessor(name) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/epuber/server.rb', line 55 def self.instance_class_accessor(name) instance_name = "@#{name}" define_singleton_method(name) do instance_variable_get(instance_name) end define_singleton_method("#{name}=") do |new_value| instance_variable_set(instance_name, new_value) end define_method(name) do self.class.send(name) end define_method("#{name}=") do |new_value| self.class.send("#{name}=", new_value) end end |
.notify_clients(type, data = nil) ⇒ Object
388 389 390 391 392 393 394 395 396 397 |
# File 'lib/epuber/server.rb', line 388 def self.notify_clients(type, data = nil) _log :info, "Notifying clients with type #{type.inspect}" raise "Not known type `#{type}`" unless [:styles, :reload, :compile_start, :compile_end].include?(type) = { name: type, } [:data] = data unless data.nil? send_to_clients(.to_json) end |
.relative_path_to_book_file(path) ⇒ String
238 239 240 241 242 |
# File 'lib/epuber/server.rb', line 238 def self.relative_path_to_book_file(path) file = file_resolver.file_with_source_path(path) return if file.nil? file.pkg_destination_path end |
.reload_bookspec ⇒ Object
332 333 334 335 336 337 338 339 340 341 342 343 |
# File 'lib/epuber/server.rb', line 332 def self.reload_bookspec last_target = target Config.instance.bookspec = nil self.book = Config.instance.bookspec if (new_target = book.target_named(last_target.name)) self.target = new_target else self.target = book.targets.first _log :ui, "[!] Not found previous target after reloading bookspec file, jumping to first #{self.target.name}" end end |
.render_bade(file_path) ⇒ String
61 62 63 64 65 66 |
# File 'lib/epuber/server/handlers.rb', line 61 def self.render_bade(file_path) renderer = Bade::Renderer.from_file(file_path) .with_locals(book: book, target: target, file_resolver: file_resolver) renderer.render(new_line: '', indent: '') end |
.run!(book, target, verbose: false) ⇒ Object
Returns nil.
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/epuber/server.rb', line 107 def self.run!(book, target, verbose: false) Encoding.default_internal = Encoding::UTF_8 if Encoding.default_internal.nil? self.book = book self.target = target self.verbose = verbose start_listening_if_needed old_stderr = $stderr $stderr = StringIO.new unless verbose super() do |server| $stderr = old_stderr puts "Started development server on #{server.host}:#{server.port}" host = if server.host == '0.0.0.0' 'localhost' else server.host end yield URI("http://#{host}:#{server.port}") if block_given? end end |
.send_to_clients(message) ⇒ Object
379 380 381 382 383 384 385 |
# File 'lib/epuber/server.rb', line 379 def self.send_to_clients() _log :info, "sending message to clients #{.inspect}" sockets.each do |ws| ws.send() end end |
.sockets ⇒ Object
97 98 99 |
# File 'lib/epuber/server.rb', line 97 def self.sockets @sockets ||= [] end |
.start_listening_if_needed ⇒ Object
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/epuber/server.rb', line 154 def self.start_listening_if_needed return unless self.listener.nil? self.listener = Listen.to(Config.instance.project_path, debug: true) do |modified, added, removed| begin changes_detected(modified, added, removed) rescue => e # print error, do not send error further, listener will die otherwise $stderr.puts e $stderr.puts e.backtrace end end listener.ignore(%r{\.idea}) listener.ignore(%r{#{Config.instance.working_path}}) listener.ignore(%r{#{Config::WORKING_PATH}/}) listener.start end |
.verbose=(verbose) ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/epuber/server.rb', line 133 def self.verbose=(verbose) @verbose = verbose @default_thin_logger ||= Thin::Logging.logger unless verbose Thin::Logging.logger = Logger.new(nil) Thin::Logging.logger.level = :fatal else Thin::Logging.logger = @default_thin_logger end set :logging, verbose end |
Instance Method Details
#_log(level, message) ⇒ Object
207 208 209 |
# File 'lib/epuber/server.rb', line 207 def _log(level, ) self.class._log(level, ) end |
#add_auto_refresh_script(html_doc) ⇒ Object
283 284 285 286 287 288 289 |
# File 'lib/epuber/server.rb', line 283 def add_auto_refresh_script(html_doc) add_file_to_head(:js, html_doc, 'auto_refresh/reloader.coffee') add_file_to_head(:js, html_doc, 'auto_refresh/connector.coffee') add_file_to_head(:js, html_doc, 'auto_refresh/protocol.coffee') add_file_to_head(:js, html_doc, 'auto_refresh/auto_refresh.coffee') add_script_to_head(html_doc, 'var auto_refresh = new AutoRefresh(window, console);') end |
#add_file_to_head(type, html_doc, file_path) ⇒ Object
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/epuber/server.rb', line 301 def add_file_to_head(type, html_doc, file_path) head = html_doc.at_css('head') node = case type when :style html_doc.create_element('link', href: "/server/raw/#{file_path}" ,rel: 'stylesheet', type: 'text/css') when :js html_doc.create_element('script', src: "/server/raw/#{file_path}", type: 'text/javascript') else raise "Unknown file type `#{type}`" end return if head.css('script, link').any? { |n| (!n['href'].nil? && n['href'] == node['href']) || (!n['src'].nil? && n['src'] == node['src']) } head.add_child(node) end |
#add_keyboard_control_script(html_doc, previous_path, next_path) ⇒ Object
293 294 295 296 297 |
# File 'lib/epuber/server.rb', line 293 def add_keyboard_control_script(html_doc, previous_path, next_path) add_script_file_to_head(html_doc, 'keyboard_control.coffee', '$previous_path' => previous_path, '$next_path' => next_path) end |
#add_meta_to_head(name, content, html_doc, force: false) ⇒ Object
321 322 323 324 325 326 327 328 329 330 |
# File 'lib/epuber/server.rb', line 321 def (name, content, html_doc, force: false) head = html_doc.at_css('head') = head.at_css("meta[name=\"#{name}\"]") return if force == false && !.nil? ||= html_doc.create_element('meta') ['name'] = name ['content'] = content head.add_child() end |
#add_script_file_to_head(html_doc, file_name, *args) ⇒ Object
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/epuber/server.rb', line 244 def add_script_file_to_head(html_doc, file_name, *args) source = File.read(File.("server/#{file_name}", File.dirname(__FILE__))) if File.extname(file_name) == '.coffee' source = CoffeeScript.compile(source) end args.each do |hash| hash.each do |key, value| opt_value = if value "'#{value}'" else 'null' end source.gsub!(key, opt_value) end end source = yield source if block_given? add_script_to_head(html_doc, source) end |
#add_script_to_head(html_doc, script_text) ⇒ Object
269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/epuber/server.rb', line 269 def add_script_to_head(html_doc, script_text) script_node = html_doc.create_element('script', script_text, type: 'text/javascript') head = html_doc.at_css('head') if head.nil? head = html_doc.create_element('head') html_doc.at_css('html').add_child(head) end head.add_child(script_node) end |
#book ⇒ Epuber::Book::Book
75 |
# File 'lib/epuber/server.rb', line 75 instance_class_accessor :book |
#build_path ⇒ String
Returns base path.
182 183 184 |
# File 'lib/epuber/server.rb', line 182 def build_path self.class.build_path end |
#file_resolver ⇒ Epuber::Compiler::FileResolver
87 |
# File 'lib/epuber/server.rb', line 87 instance_class_accessor :file_resolver |
#find_file(pattern = params[:splat].first, source_path: build_path) ⇒ String
Returns path to file.
220 221 222 223 |
# File 'lib/epuber/server.rb', line 220 def find_file(pattern = params[:splat].first, source_path: build_path) finder = Compiler::FileFinders::Normal.new(source_path) finder.find_files(pattern).first end |
#handle_bade(file_path) ⇒ (Fixnum, String)
50 51 52 53 54 55 |
# File 'lib/epuber/server/handlers.rb', line 50 def handle_bade(file_path) [200, self.class.render_bade(file_path)] rescue => e env['sinatra.error'] = e ShowExceptions.new(self).call(env) end |
#handle_file(file_path) ⇒ Object
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 |
# File 'lib/epuber/server.rb', line 487 def handle_file(file_path) return not_found unless File.exists?(file_path) last_modified(File.mtime(file_path)) case File.extname(file_path) when '.styl' content_type('text/css') body(Stylus.compile(::File.new(file_path))) when '.coffee' content_type('text/javascript') body(CoffeeScript.compile(::File.read(file_path))) else extname = File.extname(file_path) type = unless Compiler::FileFinders::BINARY_EXTENSIONS.include?(extname) mime_type = MIME::Types.of(file_path).first if mime_type.nil? 'text/plain' else content_type end end send_file(file_path, type: type) end end |
#handle_server_bade(file_name) ⇒ (Fixnum, String)
42 43 44 |
# File 'lib/epuber/server/handlers.rb', line 42 def handle_server_bade(file_name) handle_bade(File.("pages/#{file_name}", File.dirname(__FILE__))) end |
#handle_websocket(path) ⇒ Object
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 |
# File 'lib/epuber/server.rb', line 455 def handle_websocket(path) _log :ws, "#{path}: start" request.websocket do |ws| thread = nil ws.onopen do sockets << ws ws.send({name: :hello}.to_json) thread = Thread.new do loop do sleep(10) ws.send({name: :heartbeat}.to_json) end end end ws. do |msg| _log :ws, "#{path}: received message: #{msg.inspect}" end ws.onclose do _log :ws, "#{path}: socket closed" sockets.delete(ws) thread.kill end end end |
#handle_xhtml_file(file_path) ⇒ (Fixnum, String)
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/epuber/server/handlers.rb', line 11 def handle_xhtml_file(file_path) html_doc = Nokogiri::XML(File.open(file_path)) add_file_to_head(:js, html_doc, 'vendor/bower/jquery/jquery.min.js') add_file_to_head(:js, html_doc, 'vendor/bower/spin/spin.js') add_file_to_head(:js, html_doc, 'vendor/bower/cookies/cookies.min.js') add_file_to_head(:js, html_doc, 'vendor/bower/uri/URI.min.js') add_file_to_head(:js, html_doc, 'vendor/bower/keymaster/keymaster.js') add_file_to_head(:style, html_doc, 'book_content.styl') add_file_to_head(:js, html_doc, 'support.coffee') (:viewport, 'width=device-width, initial-scale=1.0', html_doc) add_auto_refresh_script(html_doc) unless file_resolver.nil? current_index = file_resolver.spine_files.index { |file| file.final_destination_path == file_path } unless current_index.nil? previous_path = spine_file_at(current_index - 1).try(:pkg_destination_path) next_path = spine_file_at(current_index + 1).try(:pkg_destination_path) add_keyboard_control_script(html_doc, previous_path, next_path) end end [200, html_doc.to_xhtml] end |
#listener ⇒ Listener
103 |
# File 'lib/epuber/server.rb', line 103 instance_class_accessor :listener |
#sockets ⇒ Array<SinatraWebsocket::Connection>
95 |
# File 'lib/epuber/server.rb', line 95 instance_class_accessor :sockets |
#spine ⇒ Array<Epuber::Compiler::File>
91 |
# File 'lib/epuber/server.rb', line 91 instance_class_accessor :spine |
#spine_file_at(index) ⇒ Epuber::Book::File?
228 229 230 231 232 |
# File 'lib/epuber/server.rb', line 228 def spine_file_at(index) if !file_resolver.nil? && index >= 0 && index < file_resolver.spine_files.count file_resolver.spine_files[index] end end |
#target ⇒ Epuber::Book::Target
79 |
# File 'lib/epuber/server.rb', line 79 instance_class_accessor :target |
#verbose ⇒ FalseClass, TrueClass
83 |
# File 'lib/epuber/server.rb', line 83 instance_class_accessor :verbose |