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_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.
138 139 140 141 142 143 |
# File 'lib/epuber/server.rb', line 138 def initialize super _log :ui, 'Init compile' self.class.compile_book end |
Class Method Details
._compile_book ⇒ Object
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/epuber/server.rb', line 321 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.
183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/epuber/server.rb', line 183 def self._log(level, ) case level when :ui puts when :info puts "INFO: #{message}" if verbose when :get puts " GET: #{message}" if verbose when :ws puts " WS: #{message}" if verbose else raise "Unknown log level #{level}" end end |
.build_path ⇒ String
Returns base path.
167 168 169 |
# File 'lib/epuber/server.rb', line 167 def self.build_path Epuber::Config.instance.build_path(target) end |
.changes_detected(_modified, _added, _removed) ⇒ Object
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
# File 'lib/epuber/server.rb', line 388 def self.changes_detected(_modified, _added, _removed) all_changed = (_modified + _added + _removed).uniq 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
337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
# File 'lib/epuber/server.rb', line 337 def self.compile_book(&completion) if !@compilation_thread.nil? && @compilation_thread.status != false @compilation_thread.kill @compilation_thread = nil end if completion.nil? _compile_book else @compilation_thread = Thread.new do completion.call(_compile_book) end end end |
.filter_not_project_files(files_paths) ⇒ Array<String>
378 379 380 381 382 |
# File 'lib/epuber/server.rb', line 378 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
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/epuber/server.rb', line 54 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
363 364 365 366 367 368 369 370 371 372 |
# File 'lib/epuber/server.rb', line 363 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
229 230 231 232 233 |
# File 'lib/epuber/server.rb', line 229 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
308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'lib/epuber/server.rb', line 308 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
60 61 62 63 64 65 |
# File 'lib/epuber/server/handlers.rb', line 60 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.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/epuber/server.rb', line 106 def self.run!(book, target, verbose: false) 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}" yield URI("http://#{server.host}:#{server.port}") if block_given? end end |
.send_to_clients(message) ⇒ Object
354 355 356 357 358 359 360 |
# File 'lib/epuber/server.rb', line 354 def self.send_to_clients() _log :info, "sending message to clients #{message.inspect}" sockets.each do |ws| ws.send() end end |
.sockets ⇒ Object
96 97 98 |
# File 'lib/epuber/server.rb', line 96 def self.sockets @sockets ||= [] end |
.start_listening_if_needed ⇒ Object
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/epuber/server.rb', line 145 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
124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/epuber/server.rb', line 124 def self.verbose=(verbose) @verbose = verbose @default_thin_logger ||= Thin::Logging.logger unless verbose Thin::Logging.logger = Logger.new(nil) Thin::Logging.logger.level = nil else Thin::Logging.logger = @default_thin_logger end set :logging, verbose end |
Instance Method Details
#_log(level, message) ⇒ Object
198 199 200 |
# File 'lib/epuber/server.rb', line 198 def _log(level, ) self.class._log(level, ) end |
#add_auto_refresh_script(html_doc) ⇒ Object
274 275 276 277 278 279 280 |
# File 'lib/epuber/server.rb', line 274 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
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/epuber/server.rb', line 292 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
284 285 286 287 288 |
# File 'lib/epuber/server.rb', line 284 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_script_file_to_head(html_doc, file_name, *args) ⇒ Object
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/epuber/server.rb', line 235 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
260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/epuber/server.rb', line 260 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
74 |
# File 'lib/epuber/server.rb', line 74 instance_class_accessor :book |
#build_path ⇒ String
Returns base path.
173 174 175 |
# File 'lib/epuber/server.rb', line 173 def build_path self.class.build_path end |
#file_resolver ⇒ Epuber::Compiler::FileResolver
86 |
# File 'lib/epuber/server.rb', line 86 instance_class_accessor :file_resolver |
#find_file(pattern = params[:splat].first, source_path: build_path) ⇒ String
Returns path to file.
211 212 213 214 |
# File 'lib/epuber/server.rb', line 211 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)
49 50 51 52 53 54 |
# File 'lib/epuber/server/handlers.rb', line 49 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
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 |
# File 'lib/epuber/server.rb', line 462 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)
41 42 43 |
# File 'lib/epuber/server/handlers.rb', line 41 def handle_server_bade(file_name) handle_bade(File.("pages/#{file_name}", File.dirname(__FILE__))) end |
#handle_websocket(path) ⇒ Object
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
# File 'lib/epuber/server.rb', line 430 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 |
# 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') 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_html] end |
#listener ⇒ Listener
102 |
# File 'lib/epuber/server.rb', line 102 instance_class_accessor :listener |
#sockets ⇒ Array<SinatraWebsocket::Connection>
94 |
# File 'lib/epuber/server.rb', line 94 instance_class_accessor :sockets |
#spine ⇒ Array<Epuber::Compiler::File>
90 |
# File 'lib/epuber/server.rb', line 90 instance_class_accessor :spine |
#spine_file_at(index) ⇒ Epuber::Book::File?
219 220 221 222 223 |
# File 'lib/epuber/server.rb', line 219 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
78 |
# File 'lib/epuber/server.rb', line 78 instance_class_accessor :target |
#verbose ⇒ FalseClass, TrueClass
82 |
# File 'lib/epuber/server.rb', line 82 instance_class_accessor :verbose |