I need to create a streaming webapp with Sinatra, I try to use a single "source" of streaming when i have multiples connections open, what's the best way to do it?
I can't test before fews days but my primary idea is something like this :
set :server, :thin
connections = []
configure do
EventMachine::PeriodicTimer.new(1) do
connections.each { |out| out << "test" << "\n" }
end
end
get '/' do
stream(:keep_open) { |out| connections << out }
end
In case you didn't manage to make it work:
require 'sinatra/base'
class MyApp < Sinatra::Base
set :path, '/tmp'
set :environment, 'production'
def initialize
#connections = []
EM::next_tick do
EM::add_periodic_timer(1) do
#connections.each do |out|
out << "test" << "</br>"
end
end
end
end
get '/' do
stream(:keep_open) do |out|
#connections << out
end
end
end
run MyApp.new
I always prefer to use a proper class for sinatra applications, in this case it allows storing the connections without relying on global or pseudo global variables.
Related
I am trying to add a procedure to pop-up a modal dialog inside a plug-in.
Its purpose is to query a response at designated steps within the control-flow of the plug-in (not just acquire parameters at its start).
I have tried using gtk - I get a dialog but it is asynchronous - the plugin continues execution. It needs to operate as a synchronous function.
I have tried registering a plugin in order to take advantage of the gimpfu start-up dialogue for same. By itself, it works; it shows up in the procedural db when queried. But I never seem to be able to actually invoke it from within another plug-in - its either an execution error or wrong number of arguments no matter how many permutations I try.
[Reason behind all of this nonsense: I have written a lot of extension Python scripts for PaintShopPro. I have written a App package (with App.Do, App.Constants, Environment and the like that lets me begin to port those scripts to GIMP -- yes it is perverse, and yes sometimes the code just has to be rewritten, but for a lot of what I actual use in the PSP.API it is sufficient.
However, debugging and writing the module rhymes with witch. So. I am trying to add emulation of psp's "SetExecutionMode" (ie interactive). If
set, the intended behavior is that the App.Do() method will "pause" after/before it runs the applicable psp emulation code by popping up a simple message dialog.]
A simple modal dialogue within a gimp python-fu plug-in can be implemented via gtk's Dialog interface, specifically gtk.MessageDialog.
A generic dialog can be created via
queryDialogue = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT \
gtk.MESSAGE_QUESTION, \
gtk.BUTTONS_OK_CANCEL, "")
Once the dialog has been shown,
a synchronous response may be obtained from it
queryDialogue.show()
response = queryDialogue.run()
queryDialogue.hide()
The above assumes that the dialog is not created and thence destroyed after each use.
In the use case (mentioned in the question) of a modal dialog to manage single stepping through a pspScript in gimp via an App emulator package, the dialogue message contents need to be customized for each use. [Hence, the "" for the message argument in the Constructor. [more below]]
In addition, the emulator must be able to accept a [cancel] response to 'get out of Dodge' - ie quit the entire plug-in (gracefully). I could not find a gimpfu interface for the latter, (and do not want to kill the app entirely via gimp.exit()). Hence, this is accomplished by raising a custom Exception class [appTerminate] within the App pkg and catching the exception in the outer-most scope of the plugin. When caught, then, the plug-in returns (exits).[App.Do() can not return a value to indicate continue/exit/etc, because the pspScripts are to be included verbatim.]
The following is an abbreviated skeleton of the solution -
a plug-in incorporating (in part) a pspScript
the App.py pkg supplying the environment and App.Do() to support the pspScript
a Map.py pkg supporting how pspScripts use dot-notation for parameters
App.py demonstrates creation, customization and use of a modal dialog - App.doContinue() displays the dialogue illustrating how it can be customized on each use.
App._parse() parses the pspScript (excerpt showing how it determines to start/stop single-step via the dialogue)
App._exec() implements the pspScript commands (excerpt showing how it creates the dialogue, identifies the message widget for later customization, and starts/stops its use)
# App.py (abbreviated)
#
import gimp
import gtk
import Map # see https://stackoverflow.com/questions/2352181/how-to- use-a-dot-to-access-members-of-dictionary
from Map import *
pdb = gimp.pdb
isDialogueAvailable = False
queryDialogue = None
queryMessage = None
Environment = Map({'executionMode' : 1 })
_AutoActionMode = Map({'Match' : 0})
_ExecutionMode = Map({'Default' : 0}, Silent=1, Interactive=2)
Constants = Map({'AutoActionMode' : _AutoActionMode}, ExecutionMode=_ExecutionMode ) # etc...
class appTerminate(Exception): pass
def Do(eNvironment, procedureName, options = {}):
global appTerminate
img = gimp.image_list()[0]
lyr = pdb.gimp_image_get_active_layer(img)
parsed = _parse(img, lyr, procedureName, options)
if eNvironment.executionMode == Constants.ExecutionMode.Interactive:
resp = doContinue(procedureName, parsed.detail)
if resp == -5: # OK
print procedureName # log to stdout
if parsed.valid:
if parsed.isvalid:
_exec(img, lyr, procedureName, options, parsed, eNvironment)
else:
print "invalid args"
else:
print "invalid procedure"
elif resp == -6: # CANCEL
raise appTerminate, "script cancelled"
pass # terminate plugin
else:
print procedureName + " skipped"
pass # skip execution, continue
else:
_exec(img, lyr, procedureName, options, parsed, eNvironment)
return
def doContinue(procedureName, details):
global queryMessage, querySkip, queryDialogue
# - customize the dialog -
if details == "":
msg = "About to execute procedure \n "+procedureName+ "\n\nContinue?"
else:
msg = "About to execute procedure \n "+procedureName+ "\n\nDetails - \n" + details +"\n\nContinue?"
queryMessage.set_text(msg)
queryDialogue.show()
resp = queryDialogue.run() # get modal response
queryDialogue.hide()
return resp
def _parse(img, lyr, procedureName, options):
# validate and interpret App.Do options' semantics vz gimp
if procedureName == "Selection":
isValid=True
# ...
# parsed = Map({'valid' : True}, isvalid=True, start=Start, width=Width, height=Height, channelOP=ChannelOP ...
# /Selection
# ...
elif procedureName == "SetExecutionMode":
generalOptions = options['GeneralSettings']
newMode = generalOptions['ExecutionMode']
if newMode == Constants.ExecutionMode.Interactive:
msg = "set mode interactive/single-step"
else:
msg = "set mode silent/run"
parsed = Map({'valid' : True}, isvalid=True, detail=msg, mode=newMode)
# /SetExecutionMode
else:
parsed = Map({'valid' : False})
return parsed
def _exec(img, lyr, procedureName, options, o, eNvironment):
global isDialogueAvailable, queryMessage, queryDialogue
#
try:
# -------------------------------------------------------------------------------------------------------------------
if procedureName == "Selection":
# pdb.gimp_rect_select(img, o.start[0], o.start[1], o.width, o.height, o.channelOP, ...
# /Selection
# ...
elif procedureName == "SetExecutionMode":
generalOptions = options['GeneralSettings']
eNvironment.executionMode = generalOptions['ExecutionMode']
if eNvironment.executionMode == Constants.ExecutionMode.Interactive:
if isDialogueAvailable:
queryDialogue.destroy() # then clean-up and refresh
isDialogueAvailable = True
queryDialogue = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, "")
queryDialogue.set_title("psp/APP.Do Emulator")
queryDialogue.set_size_request(450, 180)
aqdContent = queryDialogue.children()[0]
aqdHeader = aqdContent.children()[0]
aqdMsgBox = aqdHeader.children()[1]
aqdMessage = aqdMsgBox.children()[0]
queryMessage = aqdMessage
else:
if isDialogueAvailable:
queryDialogue.destroy()
isDialogueAvailable = False
# /SetExecutionMode
else: # should not get here (should have been screened by parse)
raise AssertionError, "unimplemented PSP procedure: " + procedureName
except:
raise AssertionError, "App.Do("+procedureName+") generated an exception:\n" + sys.exc_info()
return
A skeleton of the plug-in itself. This illustrates incorporating a pspScript which includes a request for single-step/interactive execution mode, and thus the dialogues. It catches the terminate exception raised via the dialogue, and then terminates.
def generateWebImageSet(dasImage, dasLayer, title, mode):
try:
img = dasImage.duplicate()
# ...
bkg = img.layers[-1]
frameWidth = 52
start = bkg.offsets
end = (start[0]+bkg.width, start[1]+frameWidth)
# pspScript: (snippet included verbatim)
# SetExecutionMode / begin interactive single-step through pspScript
App.Do( Environment, 'SetExecutionMode', {
'GeneralSettings': {
'ExecutionMode': App.Constants.ExecutionMode.Interactive
}
})
# Selection
App.Do( Environment, 'Selection', {
'General' : {
'Mode' : 'Replace',
'Antialias' : False,
'Feather' : 0
},
'Start': start,
'End': end
})
# Promote
App.Do( Environment, 'SelectPromote' )
# und_so_weiter ...
except App.appTerminate:
raise AssertionError, "script cancelled"
# /generateWebImageSet
# _generateFloatingCanvasSetWeb.register -----------------------------------------
#
def generateFloatingCanvasSetWeb(dasImage, dasLayer, title):
mode="FCSW"
generateWebImageSet(dasImage, dasLayer, title, mode)
register(
"generateFloatingCanvasSetWeb",
"Generate Floating- Frame GW Canvas Image Set for Web Page",
"Generate Floating- Frame GW Canvas Image Set for Web Page",
"C G",
"C G",
"2019",
"<Image>/Image/Generate Web Imagesets/Floating-Frame Gallery-Wrapped Canvas Imageset...",
"*",
[
( PF_STRING, "title", "title", "")
],
[],
generateFloatingCanvasSetWeb)
main()
I realize that this may seem like a lot of work just to be able to include some pspScripts in a gimp plug-in, and to be able to single-step through the emulation. But we are talking about maybe 10K lines of scripts (and multiple scripts).
However, if any of this helps anyone else with dialogues inside plug-ins, etc., so much the better.
I have a problem using latest Copas in Lua 5.2.
I wrote a simple script (see below) which creates two server sockets: "RX" and "TX".
"RX" listens for messages from connected clients, "TX" transmits those messages to clients connected to "TX".
The problem is: In the beginning, after server start-up, everything works fine. But after a certain amount of messages, the "TX" server loop is not executed anymore, no more messages are transmitted.
There is no error message, nothing. It just stops working.
Am I using Copas wrong? What is the problem?
This is the (simplified) code:
local copas = require("copas")
local socket = require("socket")
local pl_class = require("pl.class")
-- Connection between a server and a client
pl_class.ClientConnection()
function ClientConnection:_init(connectionName, socketToClient)
self.connectionName = connectionName
self.socketToClient = socketToClient
self.queueMessagesToSend = {}
end
function ClientConnection:popMessageToSend()
return table.remove(self.queueMessagesToSend, 1);
end
function ClientConnection:pushMessageToSend(theMessage)
table.insert(self.queueMessagesToSend, theMessage)
end
-- Server base class
pl_class.Server()
function Server:_init(serverName, serverPort)
self.serverName = serverName
self.serverPort = serverPort
self.connectedClients = {}
end
function Server:initServing()
local server = socket.bind("*", self.serverPort)
print("[" .. self.serverName .. "] Waiting for client connections on port " .. self.serverPort .. "...")
copas.addserver(server, function(c) return self.connectionHandler(copas.wrap(c), c:getpeername()) end )
end
-- Class for send-only servers
pl_class.ServerSendOnly(Server)
function ServerSendOnly:_init(serverName, serverPort)
self:super(serverName, serverPort)
self.connectionHandler = function (socketToClient, clientHost, clientPort)
local connObject = ClientConnection(clientHost..":"..tostring(clientPort), socketToClient)
self.connectedClients[connObject.connectionName] = connObject
while true do
local currMessage = connObject:popMessageToSend()
if currMessage then
copas.send(connObject.socketToClient, currMessage)
end
copas.sleep(0.01)
end
self.connectedClients[connObject.connectionName] = nil
end
end
function ServerSendOnly:broadcastMessage(currMessage)
for connName,connObject in pairs(self.connectedClients) do
connObject:pushMessageToSend(currMessage .. "\r\n")
end
end
-- Class for receive-only servers
pl_class.ServerReceiveOnly(Server)
function ServerReceiveOnly:_init(serverName, serverPort)
self:super(serverName, serverPort)
self.queueMessagesReceived = {}
self.connectionHandler = function (socketToClient, clientHost, clientPort)
local connObject = ClientConnection(clientHost..":"..tostring(clientPort), socketToClient)
self.connectedClients[connObject.connectionName] = connObject
while true do
local currDataReceived = copas.receive(connObject.socketToClient)
if currDataReceived ~= nil then
local currInfo = {client=connObject.connectionName, data=currDataReceived}
table.insert(self.queueMessagesReceived, currInfo)
end
end
self.connectedClients[connObject.connectionName] = nil
end
end
function ServerReceiveOnly:popMessageReceived()
return table.remove(self.queueMessagesReceived, 1);
end
-- Setup servers
local serverSend = ServerSendOnly("ServerTX", 2345)
local serverReceive = ServerReceiveOnly("ServerRX", 1234)
serverSend:initServing()
serverReceive:initServing()
-- Main loop: Pass messages which arrived at the RX server to the clients
-- connected to the TX servers ("RX" and "TX" are used from the server's POV)
while true do
copas.step()
local currMessage = serverReceive:popMessageReceived()
if currMessage then
print("[" .. serverReceive.serverName .. "] MESSAGE RECEIVED FROM '" .. currMessage.client .."': " .. currMessage.data)
serverSend:broadcastMessage(currMessage.data)
end
end
I have an app file that looks like this ws_app.rb:
require 'rubygems'
require 'sinatra'
require 'sinatra/respond_to'
require 'dm-core'
require 'dm-migrations'
require 'dm-timestamps'
require 'json'
require 'csv'
load 'models/Battery.rb'
Sinatra::Application.register Sinatra::RespondTo
DataMapper::setup(:default,"sqlite3://#{Dir.pwd}/mpt_hmi.sqlite3")
class MPTHMI < Sinatra::Base
load 'controller/BatteryController.rb'
end
The modules/Battery.rb looks like this:
class Battery
include DataMapper::Resource
property :id, Serial
property :i_battery_manager_id, Integer
property :c_battery_number, String
property :c_battery_state, String
property :c_voltage_byte, String
property :i_voltage_int, Integer
property :i_temperature, Integer
property :i_resistance, Integer
property :i_capacity, Integer
property :i_cell_balancing_duration, Integer
property :i_total_cell_balancing_duration, Integer
property :i_age, Integer
property :i_time_to_service, Integer
property :created_at, DateTime
property :updated_at, DateTime
def to_my_json
{
:i_battery_manager_id => self.i_battery_manager_id,
:c_battery_number => self.c_battery_number,
:c_battery_state => self.c_battery_state,
:c_voltage_byte => self.c_voltage_byte,
:i_voltage_int => self.i_voltage_int,
:i_temperature => self.i_temperature,
:i_resistance => self.i_resistance,
:i_capacity => self.i_capacity,
:i_cell_balancing_duration => self.i_cell_balancing_duration,
:i_total_cell_balancing_duration => self.i_total_cell_balancing_duration,
:i_age => self.i_age,
:i_time_to_service => self.i_time_to_service
}
end
end
The controller/BatteryController.rb file looks like this:
get '/battery/:id' do
#battery = Battery.get(params[:id])
respond_to do |wants|
wants.html { erb :battery } # html
wants.json { #battery.to_my_json.to_s } # json
end
end
get '/batteries' do
#batteries = Battery.all
respond_to do |wants|
wants.html { erb :batteries } # html
wants.json {
#batteries.all.inject({}) { |hsh, obj|
hsh[obj.id] = obj.to_my_json
hsh
}.to_json
}
end
end
This works perfectly when I run Sinatra normally, like so:
$ ruby ws_app.rb
== Sinatra/1.3.2 has taken the stage on 4567 for development with backup from Thin
>> Thin web server (v1.3.1 codename Triple Espresso)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop
Then go here:
http://0.0.0.0:4567/battery/5.json
I get the JSON I'm expecting:
{:i_battery_manager_id=>1, :c_battery_number=>"5", :c_battery_state=>"3", :c_voltage_byte=>"145", :i_voltage_int=>191, :i_temperature=>107, :i_resistance=>81, :i_capacity=>228, :i_cell_balancing_duration=>127, :i_total_cell_balancing_duration=>37, :i_age=>111, :i_time_to_service=>211}
but I need to deploy this on a Cherokee web server, so I want to make a rack config.ru file for this...
So I have a file mpthmiws.rb which contains
load 'ws_app.rb'
MPTHMI.run
And a config.ru file which contains
load 'mpthmiws.rb'
run MPTHMI.new
When I run
$ rackup config.ru
>> Thin web server (v1.3.1 codename Triple Espresso)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:9292, CTRL+C to stop
and go here:
http://0.0.0.0:9292/battery/1.json
but then I get the famous, "Sinatra doesn't know this ditty - try get '/battery/1.json' do "Hello World" end
If I take the first route from the controller/BatteryController.rb file and put it inside HMIMPT class in the ws_app.rb file like this:
require 'rubygems'
require 'sinatra'
require 'sinatra/respond_to'
require 'dm-core'
require 'dm-migrations'
require 'dm-timestamps'
require 'json'
require 'csv'
load 'models/Battery.rb'
Sinatra::Application.register Sinatra::RespondTo
DataMapper::setup(:default,"sqlite3://#{Dir.pwd}/mpt_hmi.sqlite3")
class MPTHMI < Sinatra::Base
get '/battery/:id' do
#battery = Battery.get(params[:id])
respond_to do |wants|
wants.html { erb :battery } # html
wants.json { #battery.to_my_json.to_s } # json
end
end
end
I get this error:
undefined method `respond_to' for #<MPTHMI:0x00000001240a80>
How can I resolve this?
Thanks
First of all, that thing with mpthmiws.rb and config.ru is overly complicated. Delete mpthmiws.rb and use this config.ru for use with rackup config.ru:
require './ws_app'
run MPTHMI
If you want to run the App with plain old ruby ws_app.rb, use this run.rb file:
require './ws_app'
MPTHMI.run!
Which brings us to the next point: NEVER EVER USE load! It executes the code in the loaded file, but it does not bring over any defined variables, functions etc. Use require instead! Here you must prefix the path with ./ or add ./ to $LOAD_PATH, but in turn you can omit the .rb extension.
Next is your BatteryController.rb file. It should look like this:
require 'sinatra/respond_to'
class BatteryController < Sinatra::Base
register Sinatra::RespondTo
get '/battery/:id' do
# ...
end
get '/batteries' do
# ...
end
end
And this is also the point where you register your extensions — in the class where you need it.
Now that we understand how load works, you may already have noticed that you were not actually loading the get blocks into the MPTHMI class, but rather executing them outside of the class. That is the only reason why your app worked anyway with plain old ruby ws_app.rb!
You can properly include your controller into a class with use:
# require all your gems
# ...
require './models/Battery'
require './controller/BatteryController'
DataMapper::setup(:default,"sqlite3://#{Dir.pwd}/mpt_hmi.sqlite3")
class MPTHMI < Sinatra::Base
use BatteryController
end
You can also leave off the register in here. Feel free to comment if you have further questions!
And here's the full diff:
diff --git a/config.ru b/config.ru
index eaa15fe..1568544 100644
--- a/config.ru
+++ b/config.ru
## -1,3 +1,3 ##
-load 'mpthmiws.rb'
+require './ws_app'
-run MPTHMI.new
+run MPTHMI
diff --git a/controller/BatteryController.rb b/controller/BatteryController.rb
index 31e4910..c500c48 100644
--- a/controller/BatteryController.rb
+++ b/controller/BatteryController.rb
## -1,20 +1,27 ##
-get '/battery/:id' do
- #battery = Battery.get(params[:id])
- respond_to do |wants|
- wants.html { erb :battery } # html
- wants.json { #battery.to_my_json.to_s } # json
- end
-end
+require 'sinatra/respond_to'
-get '/batteries' do
- #batteries = Battery.all
- respond_to do |wants|
- wants.html { erb :batteries } # html
- wants.json {
- #batteries.all.inject({}) { |hsh, obj|
- hsh[obj.id] = obj.to_my_json
- hsh
- }.to_json
- }
+class BatteryController < Sinatra::Base
+ register Sinatra::RespondTo
+
+ get '/battery/:id' do
+ #battery = Battery.get(params[:id])
+ respond_to do |wants|
+ wants.html { erb :battery } # html
+ wants.json { #battery.to_my_json.to_s } # json
+ end
end
-end
+
+ get '/batteries' do
+ #batteries = Battery.all
+ respond_to do |wants|
+ wants.html { erb :batteries } # html
+ wants.json {
+ #batteries.all.inject({}) { |hsh, obj|
+ hsh[obj.id] = obj.to_my_json
+ hsh
+ }.to_json
+ }
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/mpt_hmi.sqlite3 b/mpt_hmi.sqlite3
index e69de29..9897cd9 100644
Binary files a/mpt_hmi.sqlite3 and b/mpt_hmi.sqlite3 differ
diff --git a/mpthmiws.rb b/mpthmiws.rb
deleted file mode 100644
index 87f3406..0000000
--- a/mpthmiws.rb
+++ /dev/null
## -1,3 +0,0 ##
-load 'ws_app.rb'
-
-MPTHMI.run
diff --git a/ws_app.rb b/ws_app.rb
index 1cab867..4a6e332 100644
--- a/ws_app.rb
+++ b/ws_app.rb
## -1,19 +1,18 ##
require 'rubygems'
require 'sinatra'
-require 'sinatra/respond_to'
require 'dm-core'
require 'dm-migrations'
require 'dm-timestamps'
require 'json'
require 'csv'
-load 'models/Battery.rb'
+require './models/Battery'
+require './controller/BatteryController'
-Sinatra::Application.register Sinatra::RespondTo
DataMapper::setup(:default,"sqlite3://#{Dir.pwd}/mpt_hmi.sqlite3")
class MPTHMI < Sinatra::Base
-
- load 'controller/BatteryController.rb'
+
+ use BatteryController
end
I'm having a strange problem when trying to set a callback for Facebook Authentication via Omniauth. In my controller (simplified to just the code necessary to show the error) I have:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
raise env.inspect
# auth_hash = env["omniauth.auth"]
end
end
this works in production mode, showing me the hash. However in test mode env is set to nil.
I have the following set in my spec_helper.rb file
OmniAuth.config.test_mode = true
OmniAuth.config.add_mock(:facebook, {"credentials" => {
"token" => "foo-token"
}
})
and my spec looks like this:
require 'spec_helper'
describe Users::OmniauthCallbacksController do
describe "Facebook" do
before(:each) do
request.env["devise.mapping"] = Devise.mappings[:user]
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:facebook]
end
it "should be a redirect" do
get :facebook
response.should redirect_to(root_path)
end
end
end
Can anyone enlighten me on what I need to do to have env not be nil when running my tests?
I use the following in my spec_helper.rb :
RACK_ENV = ENV['ENVIRONMENT'] ||= 'test'
I don't use Rails or Devise though so YMMV. I've also seen various threads saying that someone had to do this before their requires to get it to work.
I am trying to call a web service in rhosync application.rb, I see a 500 error response in rhosync console .. and 'server returned an error' in BB simulator .. :(
Some info about my setup -
I have created a rhodes app that connects to a rhosync app when user enters user name and password and clicks on "login". I am calling this webservice through "authenticate" method of application.rb of the rhosync application ..
def authenticate(username,password,session)
Rho::AsyncHttp.get(:url => 'http://mywebserviceURL',:callback => (url_for :action => :httpget_callback),:callback_param => "" )
end
UPDATE
Instead of http:async, I tried consuming a soap based webservice and it worked just fine .. here is code if anyone cones here in search of a sample.. in application.rb of rhosync app
require "soap/rpc/driver"
class Application < Rhosync::Base
class << self
def authenticate(username,password,session)
driver = SOAP::RPC::Driver.new('http://webserviceurl')
driver.add_method('authenticate', 'username', 'password')
ret=driver.authenticate(username,password)
if ret=="Success" then
true
else
false
end
end
end
Application.initializer(ROOT_PATH)
You can typically find the problem if you crank up your log. Edit rhoconfig.txt in your app
set these properties -
# Rhodes runtime properties
MinSeverity = 1
LogToOutput = 1
LogCategories = *
ExcludeLogCategories =
then try again and watch the terminal output. Feel free to post the log back and I'll take a look.
You also might want to echo out puts the mywebserviceURL if you're using that as a variable, I trust you just changed that for the post here. Can you access the webservice if you hit it with a browser?
require "soap/rpc/driver"
class Application < Rhosync::Base
class << self
def authenticate(username,password,session)
driver = SOAP::RPC::Driver.new('http://webserviceurl')
driver.add_method('authenticate', 'username', 'password')
ret=driver.authenticate(username,password)
if ret=="Success" then
true
else
false
end
end
end
Application.initializer(ROOT_PATH)
in this what is done in add_method and authenticate method and where it to be written.