Ewgi projects

1 view
Skip to first unread message

Davide Marquês

unread,
Oct 10, 2009, 7:28:58 AM10/10/09
to ew...@googlegroups.com
Ahoy all!

I was locally reorganizing the ewgi files/projects and just realized that I wouldn't be able to upload them to my github repo without confusing any newcomers about what the official version/structure really is.
So... I'd like to conduct a pool to check whether the changes I'm doing are compatible with the ewgi roadmap.
The main goal with the following changes is to get all generic ewgi middleware to be integrated in the same place preventing everyone from reinventing the wheel and making it easier for new projects to get started (without having to cut/copy and paste code from mochiweb/smak/yaws/...). On the long run it would be pretty cool to have ports of all of these ready to use. :)

At this point the ewgi_examples is mixing the "ewgi gateway server"'s startup logic and the example middleware.
I suggest that this middleware be moved to the ewgi project so that new projects depend solely on ewgi (and not ewgi_examples).

The smak framework contains lots of useful pieces for actually creating something using ewgi. With that in mind I'd suggest that some of the modules also get moved to the ewgi project.

One additional thing I find unfriendly is that figuring out what ewgi middleware exists consists of opening up the files and checking if they're support code or actual middleware (both in smak and the ewgi_examples projects). :\

These are the changes I implementing:
ewgi/
  src/[ewgi.app, ewgi_api.erl, ewgi_application.erl, ewgi_test.erl, ewgi_testapp.erl]
  src/middleware/<middleware folder>/[middleware files]
  src/server_gateways/[ewgi_inets.erl, ewgi_mochiweb.erl, ewgi_yaws.erl, TODO:ewgi_misultin.erl]
  src/utils/[generic support modules moved from smak and renamed/prefixed with "ewgi_util_"] <- at this moment I have the modules ewgi_util_calendar.erl, ewgi_util_cookie.erl and ewgi_util_crypto.erl.

smak/
  src/[smak.app, smak_test.erl, ...]
  src/middleware/<smak middleware folder>/[smak middleware files] <- if it had no particular smak dependencies it could be moved to ewgi/src/middleware
  src/utils/[support modules that are specific to smak]

ewgi_examples/
  deps/ewgi/
  [deps/mochiweb/] - if using the ewgi_mochiweb gateway
  [deps/smak/] - for smak based projects
  src/[...]

I'd rename the ewgi_examples project to ewgi_example_server as it would no longer contain ewgi middleware but an example of how to boot a ewgi web server and starting an ewgi-based project.

That's about it. Feedback welcomed! :)

Cheers,
Davide :)


Hunter Morris

unread,
Oct 12, 2009, 5:41:17 PM10/12/09
to ew...@googlegroups.com

On 10 Oct 2009, at 12:28, Davide Marquês wrote:

> At this point the ewgi_examples is mixing the "ewgi gateway
> server"'s startup logic and the example middleware.
> I suggest that this middleware be moved to the ewgi project so that
> new projects depend solely on ewgi (and not ewgi_examples).
>
> The smak framework contains lots of useful pieces for actually
> creating something using ewgi. With that in mind I'd suggest that
> some of the modules also get moved to the ewgi project.
>

I agree. I thought for a long time that these projects should be
separate for ideological reasons, but now it seems those reasons just
make projects impractical.

Perhaps when you have finished reorganising your fork, we can merge
the changes into the parent ewgi project.

Best,
Hunter

Davide Marquês

unread,
Oct 13, 2009, 2:01:50 PM10/13/09
to ew...@googlegroups.com
Ahoy all! :)

Just uploaded the restructured projects:
http://github.com/davide/ewgi
http://github.com/davide/ewgi_examples
http://github.com/davide/smak

Kick the tires and let me know how it goes. :)

Major changes:
 - created middleware folders to separate the ewgi middleware from the rest of the code;
 - created util folders for support modules used by more than one middleware (I argue that if it's used by a single middleware than it should be place in its folder);
 - migrated the middleware that was generic enough (as well as support modules) to the ewgi repository (that includes ewgi_deflate, ewgi_post, ewgi_session and ewgi_stream_file);
 - kept the index and to_upper middleware examples in the ewgi_examples repository - but renamed them to prevent name clashes;
 - upgraded the smak modules to reference the support modules that where moved (and renamed accordingly) to the ewgi repository;
 - started using Emakefiles for building ewgi_examples;
 - added a script to generate the .app files based on the ebin/*.beam files (questionable decision...);
 - added content to the ewgi_examples/README - with a bit discussing ewgi terminology (see if I got it right).

I'd like to migrate the remaining smak middleware (the authentication ones especially) to the ewgi project but I fear bloating the project by simply copying over all the required dependencies.
Perhaps we should discuss what are the basic/minimal pieces that should go into ewgi.

Feedback welcomed. :)

Cheers,
:Davide

Dmitrii Dimandt

unread,
Oct 22, 2009, 4:59:47 AM10/22/09
to ew...@googlegroups.com
Now, fist of all, I must say this is wow 0_o :) I love it :)

There's always a "however" lurking somewhere, of course :)

I disagree with definitions for middleware and applications:

Current version:

Ewgi Middleware:
    - any function that receives an ewgi_context() and does
      something with it. That's it. No further rules apply. :\
      
  Ewgi Application:
    - a 2 parameter function that receives an ewgi_context()
      as its first argument and a parameter list as a second argument.
      This convention/restriction from the generic "ewgi middleware"
      described above defines a stable interface that developers can
      count on when integrating 3rd party middleware.

In my opinion, the two are actually equivalent :) Since the latter is just the former, only with options. I think the real power in applications is chaining them. And there's currently no chaining method specified.

Right now middleware can only be chained sequentially like this:

Ctx1 = mw1:run(Ctx, Opts1),
Ctx2 = mw2:run(Ctx1, Opts2),
Ctx3 = mw3:run(Ctx3, Opts2)...

So, it's impossible to introduce a component that works on both the request and the response (like caching, conditional get, ETags etc.)

And yeah, I'm trying to stick my own solutions as high up as possible and wave them in front of everybody's face, but still :))

The basic idea is outlined here: 

We could extend the existing proposal for middleware like this:

Ewgi Applicaton:
A parametrized middleware module that is initialized with a single parameter, App. If the module modifies the request, it should pass the modified request to this App. If the module modifies the response, it should get the response from the app and modify it:

-module(example_mw, [App]).

run(Ctx, Options) ->
    Ctx1 = modify_request(Ctx), %% optional
    Ctx2 = App(Ctx1),
    Ctx3 = modify_response(Ctx2), %%optional
    Ctx3.

This will require slight modification to the chaining code, but will help turn any middleware component into a chainable application with just one or two lines of code.

Just my lots of 2 cents :)))

Hunter Morris

unread,
Oct 22, 2009, 5:11:42 AM10/22/09
to Dmitrii Dimandt, ew...@googlegroups.com
On 22 Oct 2009, at 09:59, Dmitrii Dimandt wrote:

> Now, fist of all, I must say this is wow 0_o :) I love it :)
>
> There's always a "however" lurking somewhere, of course :)
>
> I disagree with definitions for middleware and applications:
>
> Current version:
>
> Ewgi Middleware:
> - any function that receives an ewgi_context() and does
> something with it. That's it. No further rules apply. :\
>
> Ewgi Application:
> - a 2 parameter function that receives an ewgi_context()
> as its first argument and a parameter list as a second argument.
> This convention/restriction from the generic "ewgi middleware"
> described above defines a stable interface that developers can
> count on when integrating 3rd party middleware.
>
> In my opinion, the two are actually equivalent :) Since the latter
> is just the former, only with options. I think the real power in
> applications is chaining them. And there's currently no chaining
> method specified.
>

That's not strictly true. The ewgi specification tries to closely
follow the idea behind Python's WSGI and Ruby's Rack in that there is
no syntactic distinction between a middleware function and an
application function. Are you speaking more generally about the
example middleware and applications provided elsewhere?

> Right now middleware can only be chained sequentially like this:
>
> Ctx1 = mw1:run(Ctx, Opts1),
> Ctx2 = mw2:run(Ctx1, Opts2),
> Ctx3 = mw3:run(Ctx3, Opts2)...
>
> So, it's impossible to introduce a component that works on both the
> request and the response (like caching, conditional get, ETags etc.)

I may be completely confused here, so bear with me. What about the
following scenario (a middleware which routes to a particular
application based on the value of an X-Boolean header):

conditional_middleware(AppTrue, AppFalse) ->
F = fun(Ctx) ->
% x_boolean_value/1 just returns true or false depending on
the request header
case x_boolean_value(Ctx) of
true ->
AppTrue(Ctx);
false ->
AppFalse(Ctx)
end
end,
F.

When setting up the application, you would do:

Mw = conditional_middleware(App1, App2).

> And yeah, I'm trying to stick my own solutions as high up as
> possible and wave them in front of everybody's face, but still :))
>
> The basic idea is outlined here:
> http://groups.google.com/group/ewgi/browse_thread/thread/f9042018cb27baa3
>
> We could extend the existing proposal for middleware like this:
>
> Ewgi Applicaton:
> A parametrized middleware module that is initialized with a single
> parameter, App. If the module modifies the request, it should pass
> the modified request to this App. If the module modifies the
> response, it should get the response from the app and modify it:
>
> -module(example_mw, [App]).
>
> run(Ctx, Options) ->
> Ctx1 = modify_request(Ctx), %% optional
> Ctx2 = App(Ctx1),
> Ctx3 = modify_response(Ctx2), %%optional
> Ctx3.

I like the idea of being able to break down middleware pieces into
smaller pieces of functionality that modify only the request or the
response. Note that middleware can elect to modify both where
necessary.

How does the above "conditional_middleware" example fit into this
scheme? Also, are we talking about changing the specification here or
simply creating some common idioms provided with the implementation(s)
of the spec?

Best,
Hunter

Dmitrii Dimandt

unread,
Oct 22, 2009, 6:25:55 AM10/22/09
to ew...@googlegroups.com
I'll repost, since my previous email went directly to Hunter :)


On Oct 22, 2009, at 12:11 , Hunter Morris wrote:

On 22 Oct 2009, at 09:59, Dmitrii Dimandt wrote:

Now, fist of all, I must say this is wow 0_o :) I love it :)

There's always a "however" lurking somewhere, of course :)

I disagree with definitions for middleware and applications:

Current version:

Ewgi Middleware:
  - any function that receives an ewgi_context() and does
    something with it. That's it. No further rules apply. :\

Ewgi Application:
  - a 2 parameter function that receives an ewgi_context()
    as its first argument and a parameter list as a second argument.
    This convention/restriction from the generic "ewgi middleware"
    described above defines a stable interface that developers can
    count on when integrating 3rd party middleware.

In my opinion, the two are actually equivalent :) Since the latter is just the former, only with options. I think the real power in applications is chaining them. And there's currently no chaining method specified.


That's not strictly true.  The ewgi specification tries to closely follow the idea behind Python's WSGI and Ruby's Rack in that there is no syntactic distinction between a middleware function and an application function.  Are you speaking more generally about the example middleware and applications provided elsewhere?



Well, Rack seems to impose the concept of a callable app (next in chain) from what I see in rack middleware examples.



Right now middleware can only be chained sequentially like this:

Ctx1 = mw1:run(Ctx, Opts1),
Ctx2 = mw2:run(Ctx1, Opts2),
Ctx3 = mw3:run(Ctx3, Opts2)...

So, it's impossible to introduce a component that works on both the request and the response (like caching, conditional get, ETags etc.)

I may be completely confused here, so bear with me.  What about the following scenario (a middleware which routes to a particular application based on the value of an X-Boolean header):

conditional_middleware(AppTrue, AppFalse) ->
  F = fun(Ctx) ->
      % x_boolean_value/1 just returns true or false depending on the request header
      case x_boolean_value(Ctx) of
          true ->
              AppTrue(Ctx);
          false ->
              AppFalse(Ctx)
      end
  end,
  F.

When setting up the application, you would do:

Mw = conditional_middleware(App1, App2).

If you're trying to create a middleware stack, then every single middleware in that stack would need to be passed a reference to the next app in the chain anyway. However, I see the problem in this case, when you need to choose a different app/stack based on the input...




And yeah, I'm trying to stick my own solutions as high up as possible and wave them in front of everybody's face, but still :))

The basic idea is outlined here:
http://groups.google.com/group/ewgi/browse_thread/thread/f9042018cb27baa3

We could extend the existing proposal for middleware like this:

Ewgi Applicaton:
A parametrized middleware module that is initialized with a single parameter, App. If the module modifies the request, it should pass the modified request to this App. If the module modifies the response, it should get the response from the app and modify it:

-module(example_mw, [App]).

run(Ctx, Options) ->
  Ctx1 = modify_request(Ctx), %% optional
  Ctx2 = App(Ctx1),
  Ctx3 = modify_response(Ctx2), %%optional
  Ctx3.

I like the idea of being able to break down middleware pieces into smaller pieces of functionality that modify only the request or the response.

That's true, that's usually the best way to go



Note that middleware can elect to modify both where necessary.


Under the current scheme it can't :) Unless you specifically pass a reference to the next middleware/app in the chain. And you would have to do that for every component down the chain :)


Let's say, you have a caching middleware and a session middleware:

request ->
|
cache (if hit, return, if miss pass down)
|
session (get session cookie, retrieve data based on session, pass down)
|
web_app (spiderpig does what spiderpig does :)), pass up)
|
session (set cookie based on session data etc., pass up)
|
cache (caclulate CRC, place in cache etc., pass up)
|
response


How would you proceed in this case?




How does the above "conditional_middleware" example fit into this scheme?  Also, are we talking about changing the specification here or simply creating some common idioms provided with the implementation(s) of the spec?



Nope, just providing common idioms. I like the spec as is :) I'd only port SimplBridge's multipart to ewgi:
http://github.com/rklophaus/SimpleBridge/blob/master/src/simple_bridge_multipart.erl
:)





Best,
Hunter

Hunter Morris

unread,
Oct 22, 2009, 6:49:38 AM10/22/09
to Dmitrii Dimandt, ew...@googlegroups.com

Ok, my apologies. I was confused as to whether you were referring to
the spec or the example pieces of middleware. I see your point now.

So this kind of middleware may just be a separate idiom. Your example
below (with modify_request/1 and modify_response/1) is probably a more
common type of middleware. The specific problem I was thinking about
was regarding routing. You may want a piece of middleware to choose
an application based on the path, headers, etc.

>> Note that middleware can elect to modify both where necessary.
>>
>
> Under the current scheme it can't :) Unless you specifically pass a
> reference to the next middleware/app in the chain. And you would
> have to do that for every component down the chain :)
>
>
> Let's say, you have a caching middleware and a session middleware:
>
> request ->
> |
> cache (if hit, return, if miss pass down)
> |
> session (get session cookie, retrieve data based on session, pass
> down)
> |
> web_app (spiderpig does what spiderpig does :)), pass up)
> |
> session (set cookie based on session data etc., pass up)
> |
> cache (caclulate CRC, place in cache etc., pass up)
> |
> response
>
>
> How would you proceed in this case?

I think I see your point. You'd want something like this:

cache(App) ->
F = fun(Ctx) ->
case get_cached(Ctx) of
Ctx1 ->
Ctx1;
{error, not_found} ->
CtxToCache = App(Ctx),
add_to_cache(CtxToCache),
CtxToCache
end
end,
F.

And similarly for the session middleware? Then you would set up your
application as:

App = cache(session(web_app(Opts))).

Does that make any sense?

>> How does the above "conditional_middleware" example fit into this
>> scheme? Also, are we talking about changing the specification here
>> or simply creating some common idioms provided with the
>> implementation(s) of the spec?
>>
>
>
> Nope, just providing common idioms. I like the spec as is :) I'd
> only port SimplBridge's multipart to ewgi:
> http://github.com/rklophaus/SimpleBridge/blob/master/src/simple_bridge_multipart.erl
> :)

That sounds great.

Dmitrii Dimandt

unread,
Oct 22, 2009, 7:39:23 AM10/22/09
to Hunter Morris, ew...@googlegroups.com


Oh yeah, routing :) Mmmm.... Something like urlconf for Django.... :)


This setup doesn't allow either cache or session get to the request
data ;) Since web_app gets called first, so both cache and session
will only get the response data


>
>>> How does the above "conditional_middleware" example fit into this
>>> scheme? Also, are we talking about changing the specification
>>> here or simply creating some common idioms provided with the
>>> implementation(s) of the spec?
>>>
>>
>>
>> Nope, just providing common idioms. I like the spec as is :) I'd
>> only port SimplBridge's multipart to ewgi:
>> http://github.com/rklophaus/SimpleBridge/blob/master/src/simple_bridge_multipart.erl
>> :)
>
> That sounds great.


Hmmm... I didn't mean to say Id port it, but I guess I now have no
choice :)))) But I'll definitely look into it, since I was going to
anyway

Hunter Morris

unread,
Oct 22, 2009, 7:59:31 AM10/22/09
to Dmitrii Dimandt, ew...@googlegroups.com
On 22 Oct 2009, at 12:39, Dmitrii Dimandt wrote:

> Oh yeah, routing :) Mmmm.... Something like urlconf for Django.... :)

Yep! If we're going to convince anybody to use ewgi for web framework
projects (like webmachine, beepbeep, etc), they need to have some kind
of URL routing!

>> I think I see your point. You'd want something like this:
>>
>> cache(App) ->
>> F = fun(Ctx) ->
>> case get_cached(Ctx) of
>> Ctx1 ->
>> Ctx1;
>> {error, not_found} ->
>> CtxToCache = App(Ctx),
>> add_to_cache(CtxToCache),
>> CtxToCache
>> end
>> end,
>> F.
>>
>> And similarly for the session middleware? Then you would set up
>> your application as:
>>
>> App = cache(session(web_app(Opts))).
>>
>> Does that make any sense?
>
>
> This setup doesn't allow either cache or session get to the request
> data ;) Since web_app gets called first, so both cache and session
> will only get the response data

In my example, web_app/1 is simply a setup function that *returns* an
ewgi application. The same applies to session/1 and cache/1. Because
they are each returning a function which then calls one of its
arguments (except for web_app which does what spiderpig does), they
are called in left-to-right order. If I simplify things vastly:

-module(test).
-export([example/0]).

f(App) ->
io:format("Setting up f...~n"),
fun(Ctx) ->
io:format("f is running (calling App)~n"),
Ctx1 = App(Ctx),
io:format("f is finished~n"),
Ctx1
end.

g(App) ->
io:format("Setting up g...~n"),
fun(Ctx) ->
io:format("g is running (calling App)~n"),
Ctx1 = App(Ctx),
io:format("g is finished~n"),
Ctx1
end.

spiderpig(Opts) ->
io:format("Setting up spiderpig...~n"),
fun(Ctx) ->
io:format("Running spiderpig with opts: ~p~n", [Opts]),
Ctx
end.

example() ->
App = f(g(spiderpig([a,b,c]))),
App(dummy_context).


It gives this output:

(emacs@tempe)2> test:example().
Setting up spiderpig...
Setting up g...
Setting up f...
f is running (calling App)
g is running (calling App)
Running spiderpig with opts: [a,b,c]
g is finished
f is finished
dummy_context

These middleware functions I've defined simply return closures which
are used later in the app. If your middleware components are too
complex to be in the body of an
anonymous function (or you wanted to make use of hot code reloading):

-module(test).
-export([example/0]).

f(App) ->
fun(Ctx) -> f_mod:run(Ctx, App) end.

g(App) ->
fun(Ctx) -> g_mod:run(Ctx, App) end.

spiderpig(Opts) ->
fun(Ctx) -> spiderpig:run(Ctx, Opts) end.

And, finally (this post is getting long!), you can split up the
middleware as you mentioned:

f(App) ->
fun(Ctx) -> f_mod:rsp(App(f_mod:req(Ctx))) end.

Or, another example:

f(App, Foo, Bar) ->
fun(Ctx) -> f_mod:rsp(App(f_mod:req(Ctx, Foo)), Bar) end.

req(Ctx, baz) ->
do_something(Ctx);
req(Ctx, ok) ->
do_something_else(Ctx).

rsp(Ctx, _Ignore) ->
Ctx.


I realise those are just toy examples, but does that clear anything up?

> Hmmm... I didn't mean to say Id port it, but I guess I now have no
> choice :)))) But I'll definitely look into it, since I was going to
> anyway

Excellent. I haven't had a chance to take a close look at
SimpleBridge, but I will hopefully be able to check it out at the
weekend.

~H

Dmitrii Dimandt

unread,
Oct 22, 2009, 8:36:34 AM10/22/09
to Hunter Morris, ew...@googlegroups.com


It does... However, it seems somehow more complex from a middleware
developer's point of view. Much more flexible, yes, but also more
complex :) Or may be I'm not seeing it yet (I'm working on something
like half a dozen of PHP files right now, so my vision is very blurry).

I don't see it right now, but it looks like this could be automated
somehow. In the end I want to specify middleware to be run something
like in http://docs.djangoproject.com/en/dev/topics/http/middleware/
just throw in a list and let it handle itself :)


>> Hmmm... I didn't mean to say Id port it, but I guess I now have no
>> choice :)))) But I'll definitely look into it, since I was going to
>> anyway
>
> Excellent. I haven't had a chance to take a close look at
> SimpleBridge, but I will hopefully be able to check it out at the
> weekend.
>
> ~H

Same here :)

Davide Marquês

unread,
Oct 22, 2009, 5:39:21 PM10/22/09
to ew...@googlegroups.com, Hunter Morris
Ahoy! Hope I'm not too late to the party. :)

--- start of my own wow moment ---
Up to this point I had failed to realize the combining power of using functions that return:
  fun(Ctx) -> ... end

I mean... this piece of code:
App = cache(session(web_app(Opts))).
Is just great! :)
--- end of my own wow moment ---

Now for some code and then some bla bla on the end of the mail. :)

An alternative to writting:
conditional_middleware(AppTrue, AppFalse) ->
    F = fun(Ctx) ->

        % x_boolean_value/1 just returns true or false depending on
the request header
        case x_boolean_value(Ctx) of
            true ->
                AppTrue(Ctx);
            false ->
                AppFalse(Ctx)
        end
    end,
    F.
is this:
conditional_middleware(Ctx, [AppTrue, AppFalse]) ->

  % x_boolean_value/1 just returns true or false depending on the request header
  case x_boolean_value(Ctx) of
    true ->
      AppTrue(Ctx);
    false ->
      AppFalse(Ctx)
  end.
+ this:
F =  ewgi_application:mfa_mw(?EMAIL_MODULE, conditional_middleware, [AppTrue, AppFalse]).

As for Dmitrii's example code I'd pseudo-whack it like this**:
my_web_stack([...]) ->
  CacheSaveApp = ewgi_application:mfa_mw(cache, save, CacheOpts),
  SessionSaveApp = ewgi_application:mfa_mw(session, save, [SessionOpts, CacheSaveApp]),
  SessionedApp = ewgi_application:module_mw(web_app, [WebAppOtps, SessionSaveApp]),
  SessionFailApp = ...
  CacheMissApp = ewgi_application:mfa_mw(session, load, [SessionOpts, SessionedApp, SessionFailApp]),
  CacheHitApp = ...
  MyWebStack = ewgi_application:mfa_mw(cache, load, [CacheOpts, CacheHitApp, CacheMissApp]),
  MyWebStack.

-- cache module --

load(Ctx, [CacheOpts, CacheHitApp, CacheMissApp]) ->
    case get_cached(Ctx) of
        {ok, Ctx1} -> 
            CacheHitApp(Ctx1);
        {error, not_found} ->
            CacheMissApp(Ctx)
    end.

save(Ctx, [CacheOpts]) ->
    ! cache_save_ok?
      register error
    Ctx.

-- session module --

load(Ctx, [SessionOpts, SessionedApp, SessionFailApp]) ->
    session_load_ok?
      SessionedApp(Ctx1)
    else
      SessionFailApp(Ctx1).

save(Ctx, [SessionOpts, NextApp]) ->
    ! session_save_ok?
      register failure somewhere
    NextApp(Ctx1).

-- webapp module --

run(Ctx, [WebAppOpts, NextApp]) ->
    spiderpig doing its thing.

---------------- **bla bla about the code you just saw ----------------
I argue that this code is:
   - verbose;
   - not easily "chainable";
   - ugly;
   - damn ugly! :|

But despite that... it's:
   - configurable without touching the original middleware;
   - not-onion like!!!
       - you're not bound to return to the middleware again
       - you have full control over the order in which the middleware gets called (useful for 2 pieces of middleware that you want to be run in the same order over the request and the response)
    - generic***

***I argue that the "cache" above is more generic than this one:

cache(App) ->
    F = fun(Ctx) ->
        case get_cached(Ctx) of
            Ctx1 ->
                Ctx1;
            {error, not_found} ->
                CtxToCache = App(Ctx),
                add_to_cache(CtxToCache),
                CtxToCache
        end
    end,
    F.
because here:
    Ctx1 = get_cached(Ctx)
the cache would be responsible for fetching the data and "rendering/processing" it, while on the "cache module" above:
    Ctx1 = CacheHitApp(get_cached(Ctx))
the cache module would be responsible solely for fetching the cached data, while the "render/processing" operation is handled by CacheHitApp - a configurable/external App.

---------------- bla bla about chaining middleware ----------------

I believe Dmitrii's quest for an easy way to chain middleware is a worthy one and that Hunter's suggestion fits the bill quite nicelly.
And now for the "lurking however" ;) -> that chain can only be built when we're dealing with relatively simple middleware. It's hard to keep away from middleware that does execution flow control across Apps and when we get to that there's no simple solution in sight (from here at least).

---------------- bla bla about "application" and "middleware" ----------------

I now disagree with the definition old-Davide proposed about ewgi's "middleware" and "application". :)

Today (2009-10-22) I argue that:
  • it makes more sense to call "Application" to the 1-arity functions that receives the ewgi_context() and return another ewgi_context() AND can be freely chained with other Apps like Hunter's example showed.
    So many outstanding features make it worthy of a name. :)
  • the "middleware" name can be left to any code that operates on ewgi_context();

  • module:run(EwgiCtx, OptionList) can be just an unnamed recommendation for defining a middleware function that is directly callable AND that can safely be wrapped by module ewgi_application's functions when we want to turn it into an "application" for combining it with other apps
In old-Davide's defense: it was late and he didn't know what he was writting about. :)

Cheers,
new-Davide :)

Hunter Morris

unread,
Oct 22, 2009, 7:57:49 PM10/22/09
to Davide Marquês, ew...@googlegroups.com
On 22 Oct 2009, at 22:39, Davide Marquês wrote:

> Ahoy! Hope I'm not too late to the party. :)

You're never too late!

> I believe Dmitrii's quest for an easy way to chain middleware is a
> worthy one and that Hunter's suggestion fits the bill quite nicelly.
> And now for the "lurking however" ;) -> that chain can only be built
> when we're dealing with relatively simple middleware. It's hard to
> keep away from middleware that does execution flow control across
> Apps and when we get to that there's no simple solution in sight
> (from here at least).

I think perhaps it would be useful to create a list of desired
middleware components that we could use:

http://wiki.github.com/skarab/ewgi

As we build up a toolkit of middleware components, we will be able to
see where to make useful higher level abstractions. I agree that
chaining middleware components is extremely verbose at the moment.

It might be useful to statically define a middleware stack with a list
of tuples and fold over that, chaining them together. Something like
this:

[{dispatcher, [{"/", [{more_middleware, ...}]},
{"/foo", [{other_middleware, ...}]}]

You could even define the same code Davide pasted above and fold over
the list, building up the chain until you reach MyWebStack.

> I now disagree with the definition old-Davide proposed about ewgi's
> "middleware" and "application". :)
>
> Today (2009-10-22) I argue that:
> • it makes more sense to call "Application" to the 1-arity
> functions that receives the ewgi_context() and return another
> ewgi_context() AND can be freely chained with other Apps like
> Hunter's example showed.
> So many outstanding features make it worthy of a name. :)
> • the "middleware" name can be left to any code that operates on
> ewgi_context();
>
> • module:run(EwgiCtx, OptionList) can be just an unnamed
> recommendation for defining a middleware function that is directly
> callable AND that can safely be wrapped by module ewgi_application's
> functions when we want to turn it into an "application" for
> combining it with other apps
> In old-Davide's defense: it was late and he didn't know what he was
> writting about. :)

That makes more sense to me, too. Generally, all middleware are
applications, but not vice-versa. The crucial difference seems to be
that middleware eventually rely on some other component to either
modify the request or response (depending on where in the chain).

Meanwhile, I'm going to start merging Davide's structural changes into
my branches and do some other cleanup unless anybody else has any
objections. I think the server implementations could use some
refactoring.

Best,
Hunter

Davide Marquês

unread,
Oct 23, 2009, 8:57:13 AM10/23/09
to Hunter Morris, ew...@googlegroups.com
Ahoy again! :)

2009/10/23 Hunter Morris <hunter...@gmail.com>

I think perhaps it would be useful to create a list of desired middleware components that we could use:

http://wiki.github.com/skarab/ewgi

Nice iniciative! Just added my 2 cents there.

I won't be able to provide much feedback on work related to "wiring ewgi middleware" as I've taken a *way* different approach to wiring stuff together. It's not ewgi-specific so it's hard to "export/share" what I'm working without biasing/poisoning :) the ewgi project.
Still, various building blocks are still ewgi worthy and I'll make the effort to refactor those for use by "regular" ewgi users. :)

I now disagree with the definition old-Davide proposed about ewgi's "middleware" and "application". :)

Today (2009-10-22) I argue that:
       • it makes more sense to call "Application" to the 1-arity functions that receives the ewgi_context() and return another ewgi_context() AND can be freely chained with other Apps like Hunter's example showed.
So many outstanding features make it worthy of a name. :)
       • the "middleware" name can be left to any code that operates on ewgi_context();

       • module:run(EwgiCtx, OptionList) can be just an unnamed recommendation for defining a middleware function that is directly callable AND that can safely be wrapped by module ewgi_application's functions when we want to turn it into an "application" for combining it with other apps
In old-Davide's defense: it was late and he didn't know what he was writting about. :)

That makes more sense to me, too.  Generally, all middleware are applications, but not vice-versa.  The crucial difference seems to be that middleware eventually rely on some other component to either modify the request or response (depending on where in the chain).

I guess you meant to say: "Generally, all applications (1 arity functions, receiving ewgi_context(), ...) are middleware (N/arity functions, receiving ewgi_context(),...)".
Ping me back on this and I'll update the ewgi_examples/README, or better yet... migrate this info to ewgi/README. When time allows that is...

Meanwhile, I'm going to start merging Davide's structural changes into my branches and do some other cleanup unless anybody else has any objections.  I think the server implementations could use some refactoring.
No objections. :)
One thing regarding the server gateways: can I drop the usage of parametrized modules? I see no benefits and it's getting in the way. :/

Cheers,
Davide :)
Reply all
Reply to author
Forward
0 new messages