Code Monkey home page Code Monkey logo

angelo's People

Contributors

chewi avatar felixonmars avatar gunnarmarten avatar jc00ke avatar kenichi avatar kyledrake avatar mask avatar nagius avatar taomaree avatar tommay avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angelo's Issues

"main" style breaks with ruby 2.3.1

this commit breaks the "main" style feature added by @tommay because it makes Forwardable call method_defined? which is not present on main.

tried replacing the forward/def_delegators stuff in lib/angelo/main.rb with this but am running into errors i'm not understanding immediately:

  Angelo::Base::DSL.instance_methods.each do |bim|
    define_method bim do |*a|
      @angelo_app.__send__ bim, *a
    end
  end

Angelo leaking memory?

Last night my server was killed by the OS because it was using too much memory.
Try this simple code watching the memory usage.

require 'angelo'

class AngeloStressTest < Angelo::Base

  get '/' do
    'hello ' * 10E5
  end

  get '/gc/' do
    GC.start
    'gc started'
  end


end

s = AngeloStressTest.run!

After every request the memory usage increases and even invoking the garbage collector it never returns to the initial (more or less 33 MB on my system) or the previous value.

Exit the server?

How the hell do you exit the server programmatically? Any attempt to call @server.terminate, Thread.terminate or Kernel.exit simply results in an error message - or worse, a complete hang of the process.

Multiple before and after blocks

Just want to say first that I love this little framework, I've used celluloid as library before and this just really makes sense.

I'm building a little messaging app and I have created a few components like sessions and authentication, the problem is when I extracted them into a library I had no way to set them up before and after each request.

Because there is no rack and therefore no middleware I couldn't think of a way to wrap a request apart from before and after. I had a look at adding filters like sinatra has but I couldn't get the context for running the filter blocks right.

Maybe there is another way?

Async HTTP response patterns

Having gotten used to writing REST APIs in Node.js with Express, I'm accustomed to being able to kick off asynchronous tasks when an endpoint is hit and not send the HTTP response until a callback is called. I've failed to find any documentation that gives insight into how to do something similar with Angelo (or the underlying Reel/Celluloid).

With the documented tasks and async/futures, it seems that either the caller can't get the result of the task (async) or the caller can get the result of the task at the cost of blocking all other execution until the task is complete (futures). As a result, neither method seems to suit my goal of doing some non-blocking calculation or IO when an endpoint is hit and not returning a response to the client until the calculation is complete. It seems that my goal is not possible with Angelo. Is this correct?

Please feel free to close this issue if you feel it's irrelevant, I wasn't sure how else to get in contact with the Angelo community.

Content-Type doesn't support charset

The Content-Type header should always include a charset, at least for html, to prevent exploits. Angelo needs a way to at least specify a charset, and it would be wise to provide a default charset where appropriate for vulnerable Content-Types like text/html.

Angelo breaks with newer version of HTTP gem

A fresh installation:

$ rvm gemset empty
$ gem install http angelo

angelo.rb:

require 'angelo'

class Server < Angelo::Base
  get '/' do
    "Hello world"
  end
end
$ ruby angelo.rb
I, [2016-03-12T16:54:45.041077 #84532]  INFO -- : Celluloid 0.17.3 is running in BACKPORTED mode. [ http://git.io/vJf3J ]
I, [2016-03-12T16:54:45.334780 #84532]  INFO -- : Angelo 0.4.1
I, [2016-03-12T16:54:45.334898 #84532]  INFO -- : listening on 127.0.0.1:4567
E, [2016-03-12T16:54:52.654852 #84532] ERROR -- : Actor crashed!
NameError: uninitialized constant HTTP::Response::SYMBOL_TO_STATUS_CODE
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/angelo-0.4.1/lib/angelo.rb:97:in `log'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/angelo-0.4.1/lib/angelo/server.rb:68:in `route!'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/angelo-0.4.1/lib/angelo/server.rb:51:in `dispatch!'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/angelo-0.4.1/lib/angelo/server.rb:29:in `block in on_connection'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/reel-0.6.0/lib/reel/connection.rb:73:in `each_request'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/angelo-0.4.1/lib/angelo/server.rb:27:in `on_connection'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/reel-0.6.0/lib/reel/server.rb:50:in `call'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/reel-0.6.0/lib/reel/server.rb:50:in `handle_connection'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/celluloid-0.17.3/lib/celluloid/calls.rb:28:in `public_send'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/celluloid-0.17.3/lib/celluloid/calls.rb:28:in `dispatch'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/celluloid-0.17.3/lib/celluloid/call/async.rb:7:in `dispatch'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/celluloid-0.17.3/lib/celluloid/cell.rb:50:in `block in dispatch'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/celluloid-0.17.3/lib/celluloid/cell.rb:76:in `block in task'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/celluloid-0.17.3/lib/celluloid/actor.rb:339:in `block in task'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/celluloid-0.17.3/lib/celluloid/task.rb:44:in `block in initialize'
    /Users/kyle/.rvm/gems/ruby-2.2.3/gems/celluloid-0.17.3/lib/celluloid/task/fibered.rb:14:in `block in create'

port flag

How to be starting with for example bundle exec ruby foo.rb -p $PORT ?

RequestError in before block for eventsource always gives status 500

Thanks for fixing the before block exception bug. It now works with eventsource except that it doesn't have the special handling for getting a status other than 500 from the exception like the handle_request method does. I know you just put a new release out but I can easily work around this so don't feel the need to rush another one out.

Angelo crashes using reel 0.6.x

Hi @kenichi, I was trying angelo with reel 0.6.0.pre1 and I get the following error:

NameError: uninitialized constant WebSocket::Message
    /xxx/angelo-ef0d4892d865/lib/angelo/base.rb:274:in `block (3 levels) in <class:Base>'
    /xxx//angelo-ef0d4892d865/lib/angelo/stash.rb:88:in `block in all_each'
    /xxx/angelo-ef0d4892d865/lib/angelo/stash.rb:86:in `each'
    /xxx/angelo-ef0d4892d865/lib/angelo/stash.rb:86:in `all_each'
    /xxx/angelo-ef0d4892d865/lib/angelo/base.rb:273:in `block (2 levels) in <class:Base>'

the problem is here: the code is using a class from the old websocket parser, that has been removed with the websocket-driver integration.

How to manage push events

Hi, I'm using Angelo to build a real time UI for our system.
The application generates events in its event loop, my goal is to send them to Angelo to broadcast websockets.

I cannot find anywhere in documentation or code a way to do it in a simple way, at the moment I added a method at Angelo::Server

  class Server
    def custom_event(*args)
      @base.custom_event(*args)
    end
  end

and defined in my Angelo app

  def self.custom_event(*args)
    # do something
  end

and my main application pushes events to the server, but it seem to a workaround.

Is there an integrated method to do so? Otherwise I can try to make this code more clean and elegant and send a pull request 😉

scope option being ignored completely

You have a bug in instantiate_template_from_string, where opts aren't being passed correctly to Tilt.new. In addition, in lib/angelo/templates.rb, line 61, the code render = ->{ template.render(self, locals) } should respect the :scope option, if set.

Celluloid backport warning

When I run an angelo server, I get the warning

Celluloid 0.17.0 is running in BACKPORTED mode. [ http://git.io/vJf3J ]

If I take the recommendation from the url and require celluloid/current' before requiringangelo`, angelo throws the following error:

/Users/kyle/.rvm/gems/ruby-2.2.3/gems/angelo-0.4.1/lib/angelo/server.rb:8:in `<class:Server>': uninitialized constant Celluloid::Logger (NameError)
    from /Users/kyle/.rvm/gems/ruby-2.2.3/gems/angelo-0.4.1/lib/angelo/server.rb:6:in `<module:Angelo>'
    from /Users/kyle/.rvm/gems/ruby-2.2.3/gems/angelo-0.4.1/lib/angelo/server.rb:4:in `<top (required)>'
    from /Users/kyle/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
    from /Users/kyle/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
    from /Users/kyle/.rvm/gems/ruby-2.2.3/gems/angelo-0.4.1/lib/angelo.rb:132:in `<top (required)>'
    from /Users/kyle/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:128:in `require'
    from /Users/kyle/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:128:in `rescue in require'
    from /Users/kyle/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:39:in `require'
    from angelo.rb:2:in `<main>'

Multiple public dirs

I need to serve static files from two different folders.

Here is my idea:

  • public_dir accepts also an Array of paths, for example public_dir ['html/public', 'secret_folder']
  • If the file is found in html/public it will be served
  • otherwise, if found in secret_folder it will be served
  • otherwise it will return a 404
  • everything else will continue to work as it currently does

The biggest issue is that the method public_dir, when used as an accessor, has to return an array: to solve it I'd implement a couple of new methods called send_public_file(file_name) and public_file?(file_name), that way it's unlikely that a user will use public_dir directly in his/her code.

What do you think?
Since I need it I'm going to implement it immediately, if you think it is a valuable feature you will have a pull request in a couple of days

How to start a supervised server?

Hi,

Thanks for the elegant work.

It seems that Angelo::Base.run() uses Angelo::Server.new to start a new server instance, so I cannot call Angelo::Server.supervise_as manually like using other Celluloid actors.

Is there a recommended way to make a supervised server always available in Celluloid::Actor[]?

Server crashing on URI exception

Can reproduce with:

curl http://localhost:4567/scripts/cvslog.cgi?file=\<SCRIPT\>window.alert\<\/SCRIPT\>

The exception & stack trace:

E, [2014-09-04T21:59:51.850459 #873] ERROR -- : Angelo::Server crashed!
URI::InvalidURIError: bad URI(is not URI?): /scripts/cvslog.cgi?file=<SCRIPT>window.alert</SCRIPT>
    /home/xxxxx/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/uri/common.rb:176:in `split'
    /home/xxxxx/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/uri/common.rb:211:in `parse'
    /home/xxxxx/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/uri/common.rb:747:in `parse'
    /home/xxxxx/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/uri/common.rb:1232:in `URI'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/reel-0.5.0/lib/reel/mixins.rb:48:in `uri'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/reel-0.5.0/lib/reel/mixins.rb:52:in `path'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/angelo-0.1.21/lib/angelo/server.rb:39:in `dispatch!'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/angelo-0.1.21/lib/angelo/server.rb:23:in `block in on_connection'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/reel-0.5.0/lib/reel/connection.rb:73:in `each_request'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/angelo-0.1.21/lib/angelo/server.rb:21:in `on_connection'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/reel-0.5.0/lib/reel/server.rb:56:in `call'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/reel-0.5.0/lib/reel/server.rb:56:in `handle_connection'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/celluloid-0.15.2/lib/celluloid/calls.rb:25:in `public_send'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/celluloid-0.15.2/lib/celluloid/calls.rb:25:in `dispatch'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/celluloid-0.15.2/lib/celluloid/calls.rb:122:in `dispatch'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/celluloid-0.15.2/lib/celluloid/actor.rb:322:in `block in handle_message'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/celluloid-0.15.2/lib/celluloid/actor.rb:416:in `block in task'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/celluloid-0.15.2/lib/celluloid/tasks.rb:55:in `block in initialize'
    /home/xxxxx/.rvm/gems/ruby-2.1.1@app/gems/celluloid-0.15.2/lib/celluloid/tasks/task_fiber.rb:13:in `block in create'
W, [2014-09-04T21:59:51.850789 #873]  WARN -- : Terminating task: type=:call, meta={:method_name=>:run}, status=:iowait

Can Celluloid::Reel supervisors be used to ensure fault tolerance? How would I implement this with Angelo?

Actor crashed! Reel::StateError

At least twice Angelo crashed with the following stack trace:

E, [2014-12-01T07:36:36.555571 #9954] ERROR -- : Actor crashed!
Reel::StateError: already processing a request
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/reel-0.5.0/lib/reel/connection.rb:55:in `request'
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/reel-0.5.0/lib/reel/connection.rb:72:in `each_request'
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/angelo-0.2.4/lib/angelo/server.rb:23:in `on_connection'
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/reel-0.5.0/lib/reel/server.rb:56:in `call'
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/reel-0.5.0/lib/reel/server.rb:56:in `handle_connection'
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/celluloid-0.16.0/lib/celluloid/calls.rb:26:in `public_send'
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/celluloid-0.16.0/lib/celluloid/calls.rb:26:in `dispatch'
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/celluloid-0.16.0/lib/celluloid/calls.rb:122:in `dispatch'
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/celluloid-0.16.0/lib/celluloid/cell.rb:60:in `block in invoke'
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/celluloid-0.16.0/lib/celluloid/cell.rb:71:in `block in task'
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/celluloid-0.16.0/lib/celluloid/actor.rb:357:in `block in task'
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/celluloid-0.16.0/lib/celluloid/tasks.rb:57:in `block in initialize'
    /home/koala/.rvm/gems/ruby-2.1.0@ufficio/gems/celluloid-0.16.0/lib/celluloid/tasks/task_fiber.rb:15:in `block in create'

It seems somehow related to those Reel issues: celluloid/reel#150 and celluloid/reel#146

Do you have any idea?

(Yes, I did not update yet that machine to Angelo 0.3.2, but AFAIK you did not change anything about request management... I'm going to update it asap, anyway)

Crash on Ctrl+C

Issuing a Ctrl+C to shutdown the server results in a stack dump.

Environment details:

C:\src\exlite\mockEo>jruby -v
jruby 9.0.0.0.rc1 (2.2.2) 2015-06-10 a0bf3b3 Java HotSpot(TM) 64-Bit Server VM 24.79-b02 on     1.7.0_79-b15 +jit [Windows 7-amd64]


C:\src\exlite\mockEo>jruby -S gem

*** LOCAL GEMS ***
angelo (0.4.1)
...
reel (0.5.0)
...

Crash message:

    C:\src\exlite\mockEo>jruby web_server.rb
    I, [2015-06-15T09:21:25.229000 #7940]  INFO -- : Angelo 0.4.1
    I, [2015-06-15T09:21:25.229000 #7940]  INFO -- : listening on localhost:4566
    I, [2015-06-15T09:22:01.676000 #7940]  INFO -- : 127.0.0.1 - - "POST /bid_set HTTP/1.1" 404 -
    ^C
    C:\src\exlite\mockEo>W, [2015-06-15T09:23:32.853000 #7940]  WARN -- : Terminating task: type=:call, meta={:method_name=>:run}, statu
    s=:iowait
            Celluloid::TaskFiber backtrace unavailable. Please try `Celluloid.task_class = Celluloid::TaskThread` if you need backtraces
     here.
    E, [2015-06-15T09:23:32.869000 #7940] ERROR -- : CLEANUP CRASHED!
    Java::JavaLang::NullPointerException:
            org.jruby.util.io.OpenFile.channel(OpenFile.java:2231)
            org.jruby.RubyIO.getChannel(RubyIO.java:403)
            org.nio4r.Nio4r$Selector.deregister(Nio4r.java:188)
            org.nio4r.Nio4r$Selector$INVOKER$i$1$0$deregister.call(Nio4r$Selector$INVOKER$i$1$0$deregister.gen)
            org.jruby.RubyClass.finvoke(RubyClass.java:746)
            org.jruby.runtime.Helpers.invoke(Helpers.java:416)
            org.jruby.RubyBasicObject.callMethod(RubyBasicObject.java:374)
            org.nio4r.Nio4r$Monitor.close(Nio4r.java:422)
            org.nio4r.Nio4r$Monitor.close(Nio4r.java:413)
            org.nio4r.Nio4r$Monitor$INVOKER$i$close.call(Nio4r$Monitor$INVOKER$i$close.gen)
            org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:293)
            org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:131)
            org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:308)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:78)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:129)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:115)
            org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:77)
            org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
            org.jruby.ir.instructions.CallBase.interpret(CallBase.java:419)
            org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:324)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:78)
            org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:84)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:199)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:185)
            org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:205)
            org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:161)
            org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:292)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:78)
            org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:84)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:199)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:185)
            org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:205)
            org.jruby.internal.runtime.methods.WrapperMethod.call(WrapperMethod.java:59)
            org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:161)
            org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:292)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:78)
            org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:78)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:164)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:150)
            org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:197)
            org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:129)
            org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:308)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:78)
            org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:137)
            org.jruby.runtime.InterpretedIRBlockBody.commonYieldPath(InterpretedIRBlockBody.java:116)
            org.jruby.runtime.IRBlockBody.yieldSpecific(IRBlockBody.java:66)
            org.jruby.runtime.Block.yieldSpecific(Block.java:116)
            org.jruby.RubyKernel.loop(RubyKernel.java:1292)
            org.jruby.RubyKernel$INVOKER$s$0$0$loop.call(RubyKernel$INVOKER$s$0$0$loop.gen)
            org.jruby.internal.runtime.methods.JavaMethod$JavaMethodZeroBlock.call(JavaMethod.java:473)
            org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:273)
            org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:79)
            org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
            org.jruby.ir.instructions.CallBase.interpret(CallBase.java:419)
            org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:324)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:78)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:129)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:115)
            org.jruby.RubyClass.finvoke(RubyClass.java:541)
            org.jruby.RubyBasicObject.send19(RubyBasicObject.java:1631)
            org.jruby.RubyBasicObject$INVOKER$i$send19.call(RubyBasicObject$INVOKER$i$send19.gen)
            org.jruby.RubyKernel.public_send(RubyKernel.java:1824)
            org.jruby.RubyKernel$INVOKER$s$0$0$public_send.call(RubyKernel$INVOKER$s$0$0$public_send.gen)
            org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:77)
            org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
            org.jruby.ir.instructions.CallBase.interpret(CallBase.java:419)
            org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:324)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:78)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:129)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:115)
            org.jruby.ir.runtime.IRRuntimeHelpers.instanceSuper(IRRuntimeHelpers.java:890)
            org.jruby.ir.instructions.InstanceSuperInstr.interpret(InstanceSuperInstr.java:69)
            org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:324)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:78)
            org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:84)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:199)
            org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:185)
            org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:205)
            org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:313)
            org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:163)
            org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:292)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:78)
            org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:137)
            org.jruby.runtime.InterpretedIRBlockBody.commonYieldPath(InterpretedIRBlockBody.java:116)
            org.jruby.runtime.IRBlockBody.yieldSpecific(IRBlockBody.java:66)
            org.jruby.runtime.Block.yieldSpecific(Block.java:116)
            org.jruby.ir.runtime.IRRuntimeHelpers.yieldSpecific(IRRuntimeHelpers.java:456)
            org.jruby.ir.instructions.YieldInstr.interpret(YieldInstr.java:72)
            org.jruby.ir.interpreter.StartupInterpreterEngine.processOtherOp(StartupInterpreterEngine.java:184)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:108)
            org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:137)
            org.jruby.runtime.InterpretedIRBlockBody.commonYieldPath(InterpretedIRBlockBody.java:116)
            org.jruby.runtime.IRBlockBody.yieldSpecific(IRBlockBody.java:66)
            org.jruby.runtime.Block.yieldSpecific(Block.java:116)
            org.jruby.ir.runtime.IRRuntimeHelpers.yieldSpecific(IRRuntimeHelpers.java:456)
            org.jruby.ir.instructions.YieldInstr.interpret(YieldInstr.java:72)
            org.jruby.ir.interpreter.StartupInterpreterEngine.processOtherOp(StartupInterpreterEngine.java:184)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:108)
            org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:137)
            org.jruby.runtime.InterpretedIRBlockBody.commonYieldPath(InterpretedIRBlockBody.java:116)
            org.jruby.runtime.IRBlockBody.yieldSpecific(IRBlockBody.java:66)
            org.jruby.runtime.Block.yieldSpecific(Block.java:116)
            org.jruby.ir.runtime.IRRuntimeHelpers.yieldSpecific(IRRuntimeHelpers.java:456)
            org.jruby.ir.instructions.YieldInstr.interpret(YieldInstr.java:72)
            org.jruby.ir.interpreter.StartupInterpreterEngine.processOtherOp(StartupInterpreterEngine.java:184)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:108)
            org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:137)
            org.jruby.runtime.InterpretedIRBlockBody.commonYieldPath(InterpretedIRBlockBody.java:116)
            org.jruby.runtime.IRBlockBody.yieldSpecific(IRBlockBody.java:66)
            org.jruby.runtime.Block.yieldSpecific(Block.java:116)
            org.jruby.ir.runtime.IRRuntimeHelpers.yieldSpecific(IRRuntimeHelpers.java:456)
            org.jruby.ir.instructions.YieldInstr.interpret(YieldInstr.java:72)
            org.jruby.ir.interpreter.StartupInterpreterEngine.processOtherOp(StartupInterpreterEngine.java:184)
            org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:108)
            org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:137)
            org.jruby.runtime.InterpretedIRBlockBody.commonYieldPath(InterpretedIRBlockBody.java:116)
            org.jruby.runtime.IRBlockBody.doYield(IRBlockBody.java:146)
            org.jruby.runtime.BlockBody.yield(BlockBody.java:83)
            org.jruby.runtime.Block.yieldArray(Block.java:161)
            org.jruby.ext.fiber.ThreadFiber$1.run(ThreadFiber.java:259)
            java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
            java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
            java.lang.Thread.run(Thread.java:745)

Invalid JSON data makes the server crash

When an invalid JSON string is sent to the server, the function parse_post_body raises a ParseError and it crashes.

I think the best approach would be sending back to the client an halt 400 (BadRequest).
To do so we have a couple of ways:

  • make the params evaluation eager and catch the exception
  • every request handler is executed in a safer way and it sends the error code when an error is raised

Probably the latter is a bit better because it will make more reliable every Angelo instance without overhead.

What do you think?

public_dir cannot be absolute

If you pass an absolute directory to public_dir, it will be concatenated to the end of __FILE__, for something like this:

/Users/kyle/server/lib/Users/kyle/public

Support for PATCH

I've been using Angelo for a while now and I just noticed it doesn't support the PATCH HTTP verb. Is this on purpose? I can try submitting a PR but wanted to check first.

Angelo::Base should not parse ARGV (or at least should not crash)

Angelo::Base parses ARGV every time, even if it is embedded in another application and it raises and exception every time it founds a unknown parameter.
When I run my app (for example ruby myApp.rb -verbose), Angelo raises an error since it does not recognizes the -verbose param.

I suggest to remove completely the ARGV parsing, since it can generate unexpected bug when the main application uses the same args of Angelo or at least move them in an optional module (example: require angelo for common application, require angelo-embedded for embedding Angelo inside other apps)

angelo params parser crashes on arrays

Hi,
i have a little angelo based service which implements a POST request with content_type :json. As data an array is given.
So when i
curl -s -v -X POST -H "Content-type:application/json" -d '["1451","1452"]' "http://0.0.0.0:3005/do_sth"
it crashes with the following stacktrace:

/Users/gunnar/.rvm/gems/ruby-2.1.5@sa_media_service/gems/angelo-0.4.1/lib/angelo/params_parser.rb:64:in 'merge!' /Users/gunnar/.rvm/gems/ruby-2.1.5@sa_media_service/gems/angelo-0.4.1/lib/angelo/params_parser.rb:64:in 'initialize' /Users/gunnar/.rvm/gems/ruby-2.1.5@sa_media_service/gems/angelo-0.4.1/lib/angelo/params_parser.rb:29:in 'new' /Users/gunnar/.rvm/gems/ruby-2.1.5@sa_media_service/gems/angelo-0.4.1/lib/angelo/params_parser.rb:29:in 'parse_post_body' /Users/gunnar/.rvm/gems/ruby-2.1.5@sa_media_service/gems/angelo-0.4.1/lib/angelo/params_parser.rb:36:in 'parse_query_string_and_post_body' /Users/gunnar/.rvm/gems/ruby-2.1.5@sa_media_service/gems/angelo-0.4.1/lib/angelo/base.rb:241:in 'params'

So the params_parser always expects a hash as post_body and crashes otherwise. Though an array should be valid json too.

ArgumentError: this IO is already registered with selector

This happened a couple of times:

ERROR -- : Actor crashed!
ArgumentError: this IO is already registered with selector
    /xxx/gems/celluloid-io-0.16.2/lib/celluloid/io/reactor.rb:42:in `register'
    /xxx/gems/celluloid-io-0.16.2/lib/celluloid/io/reactor.rb:42:in `wait'
    /xxx/gems/celluloid-io-0.16.2/lib/celluloid/io/reactor.rb:26:in `wait_writable'
    /xxx/gems/celluloid-io-0.16.2/lib/celluloid/io.rb:65:in `wait_writable'
    /xxx/gems/celluloid-io-0.16.2/lib/celluloid/io/stream.rb:33:in `wait_writable'
    /xxx/gems/celluloid-io-0.16.2/lib/celluloid/io/stream.rb:63:in `rescue in block in syswrite'
    /xxx/gems/celluloid-io-0.16.2/lib/celluloid/io/stream.rb:60:in `block in syswrite'
    /xxx/gems/celluloid-io-0.16.2/lib/celluloid/io/stream.rb:389:in `synchronize'
    /xxx/gems/celluloid-io-0.16.2/lib/celluloid/io/stream.rb:58:in `syswrite'
    /xxx/gems/celluloid-io-0.16.2/lib/celluloid/io/stream.rb:355:in `do_write'
    /xxx/gems/celluloid-io-0.16.2/lib/celluloid/io/stream.rb:256:in `<<'
    /xxx/gems/reel-0.5.0/lib/reel/websocket.rb:80:in `write'
    /yyy/angelo_apis.rb:32:in `block (2 levels) in <class:AngeloApis>'
    /xxx/gems/angelo-0.4.1/lib/angelo/stash.rb:56:in `block in each'
    /xxx/gems/angelo-0.4.1/lib/angelo/stash.rb:54:in `each'
    /xxx/gems/angelo-0.4.1/lib/angelo/stash.rb:54:in `each'
    /yyy/angelo_apis.rb:32:in `block in <class:AngeloApis>'
    /xxx/gems/celluloid-0.16.0/lib/celluloid/calls.rb:26:in `public_send'
    /xxx/gems/celluloid-0.16.0/lib/celluloid/calls.rb:26:in `dispatch'
    /xxx/gems/celluloid-0.16.0/lib/celluloid/calls.rb:122:in `dispatch'
    /xxx/gems/celluloid-0.16.0/lib/celluloid/cell.rb:60:in `block in invoke'
    /xxx/gems/celluloid-0.16.0/lib/celluloid/cell.rb:71:in `block in task'
    /xxx/gems/celluloid-0.16.0/lib/celluloid/actor.rb:357:in `block in task'
    /xxx/gems/celluloid-0.16.0/lib/celluloid/tasks.rb:57:in `block in initialize'
    /xxx/gems/celluloid-0.16.0/lib/celluloid/tasks/task_fiber.rb:15:in `block in create'

calling this task:

  task :custom_event do |event|
    websockets.each { |ws| ws.write event.to_json }
  end

I saw this error a couple of times recently.
Do you think it can be an Angelo issue or can it be a problem of one of its dependency?
I found this

NoMethodError: undefined method `report_errors?' for Angelo::Server

I believe I have found a bug. In angelo/base.rb, line 287, you have:

warn e.message if report_errors?

self at this point is #<Celluloid::Proxy::Cell(Angelo::Server:0x2b23a590ec0c) @base=MyHTTPServer @options={:host=>"0.0.0.0", :port=>2347} @callback=#<Proc:0x000056474bd20df0 (lambda)> @server=#<Celluloid::IO::TCPServer:0x000056474bcffdf8 @socket=#<TCPServer:fd 15, AF_INET, 0.0.0.0, 2347>>>, which is also an instance of Angelo::Server

It does not have a method report_errors?. However, @base does, given that MyHTTPServer is a subclass of Angelo::Base.

I believe the line should be rewritten to:

warn e.message if @base.report_errors?

Allow Additional Content Types

I was working on adding support for handling arbitrary content types in responses and wanted to run my idea by you to see if you'd want it included in Angelo.

As far as I can tell only content types explicitly handled here and here are allowed in request handlers.

I'd like to a method to Angelo::Base that allows you to declare new content types in the body of the App class like add_content_type(type_alias, mime_type, klass=nil, &block). It would let you declare a symbol alias to use in request handlers, the associated mime type for the response header, and a lambda or class (with a .call(body) instance method) to process the response body.

For example if json handling wasn't built in it could be declared like this

class App < Angelo::Base
  add_content_type :json, "application/json" do |body|
    case body
    when String
       JSON.parse(body) # for the raises
       body
     when Hash
       body.to_json
     end
  end

  get '/' do
    content_type :json
    { "this" => "becomes json" }
  end  
end

or with a class

class JSONResponseBody
  def call(body)
    case body
    when String
       JSON.parse(body) # for the raises
       body
     when Hash
       body.to_json
     end
  end
end

class App < Angelo::Base
  add_content_type :json, "application/json", JSONResponseBody

  get '/' do
    content_type :json
    { "this" => "becomes json" }
  end  
end

Classic mode app unable to start up

When I try to start a classic mode app I get the following:

$ bundle exec ruby application.rb 
I, [2017-09-20T09:53:15.848154 #20898]  INFO -- : Celluloid 0.17.3 is running in BACKPORTED mode. [ http://git.io/vJf3J ]
/usr/lib/ruby/2.3.0/forwardable.rb:182:in `def_instance_delegator': undefined method `method_defined?' for main:Object (NoMethodError)
Did you mean?  method_missing
	from /usr/lib/ruby/2.3.0/forwardable.rb:157:in `block in def_instance_delegators'
	from /usr/lib/ruby/2.3.0/forwardable.rb:156:in `each'
	from /usr/lib/ruby/2.3.0/forwardable.rb:156:in `def_instance_delegators'
	from /var/lib/gems/2.3.0/gems/angelo-0.5.0/lib/angelo/main.rb:37:in `<top (required)>'
	from application.rb:1:in `require'
	from application.rb:1:in `<main>'
$ cat application.rb 
require 'angelo/main'

get "/foo" do
	"Hello world"
end

I am using angelo 0.5.0 and starting it with bundle exec ruby application.rb.

If I convert to the class based solution everything works fine.

future/async doesn't seem to be async

Hi. I'm not sure if I'm using this right, but shouldn't these be handled asyncrhonously?

require 'angelo'

class HelloApp < Angelo::Base

  task :do_stuff do
    time_of_request = Time.now
    Kernel.sleep 10
    time_after = Time.now
    "Hello to you, too. #{time_of_request}- #{time_after}"
  end

  get "/" do
    puts "processing"
    f = future :do_stuff
    f.value
  end
end

HelloApp.run!

When I hit it, they are usually serviced 10 sec apart. Occasionally one gets serviced w/in 3 sec.

Perhaps I did not use future correctly? Thank you

Angelo doesn't work with Ruby 3

Hello in 2022! We're still using Angelo for one of our projects and got an error when trying to switch to Ruby 3. The specific error seems to be related to the mustermann gem which is locked to an old version (0.4), but I guess there could be others. Any chance to update the angelo dependencies?

multipart/form-data

Does angelo support file uploads? Im trying to send file from Rails apllication to angelo server with form like

<form method="POST" enctype="multipart/form-data" action="http://127.0.0.1:4567/images">
  <div>
    <input name="image" type="file" />
  </div>
  <div>
    <input type="submit" value="Submit" />
  </div>
</form>

server code:

class SampleServer < Angelo::Base
  post '/images' do
    puts request.inspect
    puts params
  end
end

and log:

I, [2015-02-13T11:18:10.885547 #4130]  INFO -- : 127.0.0.1 - - "POST /images HTTP/1.1" 200 5
#<Reel::Request POST /images HTTP/1.1 @headers={"Host"=>"127.0.0.1:4567", "Connection"=>"keep-alive", "Content-Length"=>"3437206", "Cache-Control"=>"max-age=0", "Accept"=>"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Origin"=>"http://localhost:3000", "User-Agent"=>"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36", "Content-Type"=>"multipart/form-data; boundary=----WebKitFormBoundaryMMXfV2Ron4mihT2p", "Referer"=>"http://localhost:3000/", "Accept-Encoding"=>"gzip, deflate", "Accept-Language"=>"en-US,en;q=0.8"}>
{}

Angelo::FormEncodingError when sending param without a value

Not a big deal here, just thought I'd mention it. If you request a URL like /foo?bar then a Angelo::FormEncodingError exception is raised due to the lack of = even though this is a valid URL. I would expect bar to be present in the params hash as an empty string.

send_file enhancements

send_file has a couple of shortcomings that can be easily addressed:

  1. it does not accept absolute paths and it expects to find files in the public dir, but this behaviour is somehow limiting. In my case, for example, I generate .css files from a .scss compiler at runtime: at the moment I have to put them into the public folder, when I'd prefer to keep them somewhere else.
    For another purpose I'd like to implement a logic like:
get '/:file' do
  if public_folder_has(params[:file])
    send_file params[:file]
  else
    send_file "my_secret_folder/#{params[:file]}", absolute: true
  end
end

By the way, passing the 'absolute: true' option could be a nice way to implement it

  1. when a non existing file is passed the server raises a 500 error code with no implicit conversion of nil into String as body. We could handle it in better way for example with a 404 cod, an empty body and logging it.

What do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.