windowsrubysinatrawxruby

Embed webserver in desktop app: wxRuby and Sinatra


I would love to give my windows based desktop applications a web interface and vice versa. My desktop application is written in wxRuby and the webserver is Sinatra (using webrick). The simplest idea was just to mash them together, this does not work.

This code does not work. The webserver and gui app do not run simultaneously. The desktop application runs first, and then after it is closed; sinatra starts.

require 'wx'
require 'sinatra'
configure do set :server, 'webrick' end

get '/' do
  "Sinatra says hello"
end

class MyApp < Wx::App
  def on_init
    @frame = Wx::Frame.new( nil, -1, "Application" )
    @frame.show
  end
end

app = MyApp.new
app.main_loop

So I thought about changing the last two lines to

Thread.new do
    app = MyApp.new
    app.main_loop
end

Again. Desktop App runs until closed, then webserver starts. So I tried starting Sinatra in a Thread.

Thread.new do
    require 'sinatra'
    configure do set :server, 'webrick' end

    get '/' do
        "Sinatra says hello"
    end
end

require 'wx'

class MyApp < Wx::App
    def on_init
        @frame = Wx::Frame.new( nil, -1, "Application" )
        @frame.show
    end
end

app = MyApp.new
app.main_loop

Again. Desktop App runs until closed, then webserver starts.

Please advise, but keep in mind that I would really like to just have one process. If your solution is two processes; I would like strong inter-process communication that does not require polling.

Thanks! Jeff


Solution

  • This at least starts up, not sure if this breaks some threading rules.

    require 'win32/process'
    require 'sinatra/base'
    
    class MyWebServer < Sinatra::Base
      get '/' do
        'Hello world!'
      end
    end
    
    Thread.new do
      MyWebServer.run! :host => 'localhost', :port => 4567
    end
    
    require 'wx'
    
    class MyGui < Wx::App
        def on_init
            t = Wx::Timer.new(self, 55)
            evt_timer(55) { Thread.pass }
            t.start(1)
            evt_idle { Thread.pass }
            @frame = Wx::Frame.new( nil, -1, "Application" )
            @frame.show
            true
        end
    end
    
    app = MyGui.new
    app.main_loop