简体   繁体   中英

How do I start yaws to run in embedded mode?

I've spent several hours trying to troubleshoot this issue using the yaws documentation and web searches. The existing threads here haven't helped me.

I am new to erlang and I am trying to run yaws in embedded mode using the sample code provided on http://yaws.hyber.org/embed.yaws . I am missing something because I cannot get it to work. I have four files:

ybed.app

{application, ybed_app,
 [
  {description, "Yaws Embedded Application Test"},
  {vsn, "0.1.0"},
  {registered, []},
  {applications, [kernel, stdlib, yaws]},
  {mod, {ybed_app, []}},
  {env, []}
 ]}.

ybed_app.erl

-module(ybed_app).
-behaviour(application).

%% Application callbacks
-export([start/2,
         stop/1]).

start(_StartType, _StartArgs) ->
    case ybed_sup:start_link() of
        {ok, Pid} ->
            {ok, Pid};
        Other ->
            {error, Other}
    end.

stop(_State) ->
    ok.

ybed_sup.erl

-module(ybed_sup).
-behaviour(supervisor).

%% API
-export([start_link/0]).

%% Supervisor callbacks
-export([init/1]).

start_link() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

init([]) ->
    YBed = {ybed, {ybed,start,[]},
            permanent,2000,worker,[ybed]},
    {ok,{{one_for_all,0,1}, [YBed]}}.

ybed.erl

-module(ybed).
-compile(export_all).

start() ->
    {ok, spawn(?MODULE, run, [])}.

run() ->
    Id = "embedded",
    GconfList = [{id, Id}],
    Docroot = "/tmp",
    SconfList = [{port, 8000},
                 {servername, "foobar"},
                 {listen, {127,0,0,1}},
                 {docroot, Docroot}],
    {ok, SCList, GC, ChildSpecs} =
        yaws_api:embedded_start_conf(Docroot, SconfList, GconfList, Id),
    [supervisor:start_child(ybed_sup, Ch) || Ch <- ChildSpecs],
    yaws_api:setconf(GC, SCList),
     {ok, self()}.

When I compile it (successfully) and try to start the application, I get a return value:

{error,{not_loaded,yaws}}

When I try to run the compiled ybed.erl, ybed:run(), I get:

** exception error: undefined function yaws_api:embedded_start_conf/4
     in function  ybed:run/0 (src/ybed.erl, line 16)

If I start yaws before I start the application, it still doesn't work.

I am not trying to build releases yet, just compile and test yaws in embedded mode. Can anyone tell me what I'm missing?

Thanks in advance

When you get error

** exception error: undefined function yaws_api:embedded_start_conf/4
     in function  ybed:run/0 (src/ybed.erl, line 16)

You clearly don't have yaws_api.beam in your code server search path. Start your erl with proper -pa argument or call code:add_patha/1 in your application initialization if you are not planning use embedded mode.

BTW there is a neat way how to start yaws under your own supervisor described in yaws documentation but without complete code so here we go in one module and with neat debugging resource and preparation for REST servicing.

-module(ybed_yaws).

-behaviour(supervisor).

-include_lib("yaws/include/yaws_api.hrl").

%% API
-export([start_link/0]).

%% Supervisor callbacks
-export([init/1]).

%% Internal functions export
-export([init_yaws/1, out/1]).

%%%===================================================================
%%% Defaults
%%%===================================================================

default_global() ->
    #{id => "yaws", logdir => "log"}.

default_server() ->
    #{port => 9900,
      listen => {0,0,0,0},
      docroot => "www",
      appmods => [{"/", ?MODULE}]}.

%%%===================================================================
%%% API functions
%%%===================================================================

start_link() ->
    supervisor:start_link(?MODULE, []).

%%%===================================================================
%%% Supervisor callbacks
%%%===================================================================

init([]) ->
    {ok,
     {{one_for_all, 0, 1},
      [#{id => init_yaws,
         start => {?MODULE, init_yaws, [self()]},
         restart => transient}]
     }}.

%%%===================================================================
%%% Internal functions
%%%===================================================================

init_yaws(Sup) ->
    {ok, proc_lib:spawn_link(fun() -> config(Sup) end)}.

ensure_dir(Dir) ->
    {ok, App} = application:get_application(),
    D = filename:join([code:priv_dir(App), Dir])
    filelib:ensure_dir(filename:join([D, "foo"])),
    D.

config(Supervisor) ->
    #{id := Id} = GCMap = default_global(),
    #{docroot := DR} = SCMap = default_server(),
    Docroot = ensure_dir(DR),
    {ok, SC, GC, ChildSpecs} =
        yaws_api:embedded_start_conf(
          Docroot,
          maps:to_list(SCMap#{docroot => Docroot}),
          maps:to_list(GCMap),
          Id),
    [supervisor:start_child(Supervisor, Ch) || Ch <- ChildSpecs],
    yaws_api:setconf(GC, SC),
    ok.

-compile({inline, [h/1, f/2]}).
h(A) when is_atom(A) -> h(atom_to_binary(A, latin1));
h(S) -> yaws_api:htmlize(S).

f(Fmt, Args) -> yaws_api:f(Fmt, Args).

box(Str) ->
    {'div',[{class,"box"}],
     {pre, [], h(Str)}}.

out(A) ->
    PathString = case A#arg.pathinfo of
               undefined -> "";
               P -> P
           end,
    Path = string:tokens(PathString, "/"),
    Method = A#arg.req#http_request.method,
    out(A, Method, Path).

out(A, Method, Path) ->
    {ehtml,
     {html, [],
      [{head},
       {body, [],
        [
         {h5, [], "Paths:"},
         {hr},
         box(f("Method = ~p~n"
               "Path = ~p~n"
               "A#arg.querydata = ~p~n",
               [Method,
                Path,
                A#arg.querydata])),
         {h5, [], "Headers:"},
         {hr},
         {ol, [], yaws_api:reformat_header(
                    A#arg.headers,
                    fun(H, V)->
                            {li, [], [h(H), ": ", {code, [], h(V)}]}
                    end
                   )}
        ]}
      ]}
    }.

Note the way how is yaws initialised in OTP compliant transient process but without gen_server .

Add {yaws, [{embedded, true}]} to your .config file to keep yaws application common services from starting. It will work even without it but it will not be fully embedded.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM