Browse Source

n2o_file to n4u_file

221V 3 years ago
parent
commit
3428a02996
4 changed files with 131 additions and 83 deletions
  1. 1 1
      ebin/n4u.app
  2. 1 1
      src/endpoints/n2o_proto.erl
  3. 0 81
      src/protocols/n2o_file.erl
  4. 129 0
      src/protocols/n4u_file.erl

+ 1 - 1
ebin/n4u.app

@@ -2,7 +2,7 @@
   {description, "N4U WebSocket Application Server"},
   {vsn, "4.4.20"},
   {applications, [kernel, stdlib, asn1, public_key, ssl, crypto, ranch, cowboy, fs, active, sh, gproc, nitro]},
-  {modules, [n2o, n4u_app, n4u_sup, n4u_async, n2o_xhr, n4u_cx, n2o_cowboy, n2o_multipart, n2o_static, n2o_stream, n4u_document, n2o_proto, n2o_relay, n4u_error, n4u_io, n4u_log, n4u_mq, n2o_pickle, n2o_query, n2o_secret, n2o_session, n4u_syn, n4u_client, n2o_file, n4u_heart, n4u_http, n4u_nitrogen, n4u_text, wf, wf_convert, wf_utils]},
+  {modules, [n2o, n4u_app, n4u_sup, n4u_async, n2o_xhr, n4u_cx, n2o_cowboy, n2o_multipart, n2o_static, n2o_stream, n4u_document, n2o_proto, n2o_relay, n4u_error, n4u_io, n4u_log, n4u_mq, n2o_pickle, n2o_query, n2o_secret, n2o_session, n4u_syn, n4u_client, n4u_file, n4u_heart, n4u_http, n4u_nitrogen, n4u_text, wf, wf_convert, wf_utils]},
   {registered, [n4u_sup]},
   {mod, {n4u_app, []}},
   {env, []}

+ 1 - 1
src/endpoints/n2o_proto.erl

@@ -7,7 +7,7 @@ formatter(O)-> case lists:keyfind(formatter,1,O) of {formatter,F} -> F; X -> X e
 upack(D)    -> binary_to_term(D,[safe]).
 protocols() -> wf:config(n2o,protocols,[ n4u_heart,
                                          n4u_nitrogen,
-                                         n2o_file,
+                                         n4u_file,
                                          n4u_client,
                                          n4u_http ]).
 

+ 0 - 81
src/protocols/n2o_file.erl

@@ -1,81 +0,0 @@
--module(n2o_file).
--include_lib("n4u/include/n4u.hrl").
--include_lib("kernel/include/file.hrl").
--compile([export_all, nowarn_export_all]).
-
--define(ROOT, wf:config(n2o,upload,code:priv_dir(n2o))).
--define(NEXT, 256*1024). % 256K chunks for best 25MB/s speed
--define(STOP, 0).
-
-% Callbacks
-
-filename(#ftp{sid=Sid,filename=FileName}) -> filename:join(wf:to_list(Sid),FileName).
-
-% N2O Protocols
-
-info(#ftp{status={event,_}}=FTP, Req, State) ->
-    wf:info(?MODULE,"Event Message: ~p",[FTP#ftp{data= <<>>}]),
-    Module=State#cx.module,
-    Reply=try Module:event(FTP)
-          catch E:R -> Error=wf:stack(E,R), wf:error(?MODULE,"Catch: ~p:~p~n~p",Error), Error end,
-    {reply,wf:format({io,n4u_nitrogen:render_actions(wf:actions()),Reply}),Req,State};
-
-info(#ftp{id=Link,sid= _Sid,filename= _FileName,status= <<"init">>,block=Block,offset=Offset,size= _TotalSize}=FTP,Req,State) ->
-    Root=?ROOT,
-    RelPath=(wf:config(n2o,filename,n2o_file)):filename(FTP),
-    FilePath=filename:join(Root,RelPath),
-    ok=filelib:ensure_dir(FilePath),
-    FileSize=case file:read_file_info(FilePath) of {ok,Fi} -> Fi#file_info.size; {error,_} -> 0 end,
-
-    wf:info(?MODULE,"Info Init: ~p Offset: ~p Block: ~p~n",[FilePath,FileSize,Block]),
-
-    % Name={Sid,filename:basename(FileName)},
-    Block2=case Block of 0 -> ?STOP; _ -> ?NEXT end,
-    Offset2=case FileSize >= Offset of true -> FileSize; false -> 0 end,
-    FTP2=FTP#ftp{block=Block2,offset=Offset2,filename=RelPath,data= <<>>},
-
-    n4u_async:stop(file,Link),
-    n4u_async:start(#handler{module=?MODULE,class=file,group=n2o,state=FTP2,name=Link}),
-
-    {reply,wf:format(FTP2),Req,State};
-
-info(#ftp{id=Link,sid= _Sid,filename= _FileName,status= <<"send">>}=FTP,Req,State) ->
-    wf:info(?MODULE,"Info Send: ~p",[FTP#ftp{data= <<>>}]),
-    Reply=try gen_server:call(n4u_async:pid({file,Link}),FTP)
-        catch _E:_R -> wf:error(?MODULE,"Info Error call the sync: ~p~n",[FTP#ftp{data= <<>>}]),
-            FTP#ftp{data= <<>>,block=?STOP} end,
-    wf:info(?MODULE,"reply ~p",[Reply#ftp{data= <<>>}]),
-    {reply,wf:format(Reply),Req,State};
-
-info(#ftp{status= <<"recv">>}=FTP,Req,State) -> {reply,wf:format(FTP),Req,State};
-
-info(#ftp{status= <<"relay">>}=FTP,Req,State) -> {reply,wf:format(FTP),Req, State};
-
-info(Message,Req,State) -> wf:info(?MODULE, "Info Unknown message: ~p",[Message]),
-    {unknown,Message,Req,State}.
-
-% N2O Handlers
-
-proc(init,#handler{state=#ftp{sid=Sid}=FTP}=Async) ->
-    wf:info(?MODULE,"Proc Init: ~p",[FTP#ftp{data= <<>>}]),
-    wf:send(Sid,FTP#ftp{data= <<>>,status={event,init}}),
-    {ok,Async};
-
-proc(#ftp{id=Link,sid=Sid,data=Data,filename= _FileName,status= <<"send">>,block=Block}=FTP,
-     #handler{state=#ftp{data= _State,size=TotalSize,offset=Offset,filename=RelPath}}=Async) when Offset+Block >= TotalSize ->
-	wf:info(?MODULE,"Proc Stop ~p, last piece size: ~p", [FTP#ftp{data= <<>>},byte_size(Data)]),
-	case file:write_file(filename:join(?ROOT,RelPath),<<Data/binary>>,[append,raw]) of
-		{error,Reason} -> {reply,{error,Reason},Async};
-		ok ->
-            FTP2=FTP#ftp{data= <<>>,block=?STOP},
-            wf:send(Sid,FTP2#ftp{status={event,stop},filename=RelPath}),
-			spawn(fun() -> n4u_async:stop(file,Link) end),
-			{stop,normal,FTP2,Async#handler{state=FTP2}} end;
-
-proc(#ftp{sid= _Sid,data=Data,block=Block}=FTP,
-     #handler{state=#ftp{data= _State,offset=Offset,filename=RelPath}}=Async) ->
-    FTP2=FTP#ftp{status= <<"send">>,offset=Offset+Block },
-    wf:info(?MODULE,"Proc Process ~p",[FTP2#ftp{data= <<>>}]),
-    case file:write_file(filename:join(?ROOT,RelPath),<<Data/binary>>,[append,raw]) of
-        {error,Reason} -> {reply,{error,Reason},Async};
-        ok -> {reply,FTP2#ftp{data= <<>>},Async#handler{state=FTP2#ftp{filename=RelPath}}} end.

+ 129 - 0
src/protocols/n4u_file.erl

@@ -0,0 +1,129 @@
+-module(n4u_file).
+
+-include_lib("n4u/include/n4u.hrl").
+-include_lib("kernel/include/file.hrl").
+
+-export([filename/1, info/3, proc/2]).
+
+-define(ROOT, application:get_env(n4u, upload, code:priv_dir(n4u))).
+-define(NEXT, 256 * 1024). % 256K chunks for best 25MB/s speed
+-define(STOP, 0).
+
+
+% callback
+
+filename(#ftp{sid = _Sid, filename = File_Name}) ->
+  File_Name. % filename:join(lists:concat([Sid]), File_Name). % filename:join(nitro:to_list(Sid), File_Name). % todo check
+
+
+% N4U protocols
+
+info(#ftp{status = {event, _}} = FTP, Req, State) ->
+  wf:info(?MODULE, "Event Message: ~p", [FTP#ftp{data = <<>>}]),
+  Module = State#cx.module,
+  Reply = try Module:event(FTP)
+  catch E:R:Stk ->
+    wf:error(?MODULE, "Catch: ~p:~p~n~p", [E, R, Stk]),
+    [E, R, Stk]
+  end,
+  {reply, wf:format({io, n4u_nitrogen:render_actions(erlang:get(actions)), Reply}), Req, State};
+
+
+info(#ftp{id = Link, sid = _Sid, filename = _FileName, status = <<"init">>,
+          block = Block, offset = Offset, 'size' = _TotalSize} = FTP, Req, State) ->
+  Root = ?ROOT,
+  RelPath = (application:get_env(n4u, filename, n4u_file)):filename(FTP),
+  FilePath = filename:join(Root, RelPath),
+  ok = filelib:ensure_dir(FilePath),
+  
+  FileSize = case file:read_file_info(FilePath) of
+    {ok, Fi} -> Fi#file_info.'size'; %'
+    {error, _} -> 0
+  end,
+  
+  wf:info(?MODULE, "Info Init: ~p Offset: ~p Block: ~p~n", [FilePath, FileSize, Block]),
+  
+  %Name = {Sid, filename:basename(FileName)},
+  Block2 = case Block of
+    0 -> ?STOP;
+    _ -> ?NEXT
+  end,
+  Offset2 = case FileSize >= Offset of
+    true -> FileSize;
+    false -> 0
+  end,
+  FTP2 = FTP#ftp{block = Block2, offset = Offset2, filename = RelPath, data = <<>>},
+  
+  catch n4u_async:stop(file, Link),
+  n4u_async:start(#handler{module = ?MODULE, class = file, group = n4u, state = FTP2, name = Link}),
+  
+  {reply, wf:format(FTP2), Req, State};
+
+
+info(#ftp{id = Link, sid = _Sid, filename = _FileName, status = <<"send">>} = FTP, Req, State) ->
+  wf:info(?MODULE, "Info Send: ~p", [FTP#ftp{data = <<>>}]),
+  
+  %Reply = try n4u_async:send(n4u_async:pid({file, Link}), FTP)
+  Reply = try n4u_async:send(file, Link, FTP)
+  catch E:R:Stk ->
+    wf:error(?MODULE, "Info Error call the async: ~p~n~p:~p~n ~p~n", [FTP#ftp{data = <<>>}, E, R, Stk]),
+    FTP#ftp{data = <<>>, sid = <<>>, block = ?STOP}
+  end,
+  
+  wf:info(?MODULE, "reply ~p", [Reply#ftp{data = <<>>}]),
+  {reply, wf:format(Reply), Req, State};
+
+
+info(#ftp{status = <<"recv">>} = FTP, Req, State) ->
+  {reply, wf:format(FTP), Req, State};
+
+
+info(#ftp{status = <<"relay">>} = FTP, Req, State) ->
+  {reply, wf:format(FTP), Req, State};
+
+
+info(Message, Req, State) ->
+  wf:info(?MODULE, "Info Unknown message: ~p", [Message]),
+  {unknown, Message, Req, State}.
+
+
+
+% N4U handlers
+
+proc(init, #handler{state = #ftp{sid = Sid} = FTP} = Async) ->
+  wf:info(?MODULE, "Proc Init: ~p", [FTP#ftp{data = <<>>}]),
+  wf:send(Sid, FTP#ftp{data = <<>>, status = {event, init}}),
+  {ok, Async};
+
+
+proc(#ftp{id = Link, sid = Sid, data = Data, filename = _FileName, status = <<"send">>, block = Block} = FTP,
+     #handler{state = #ftp{data = _State, 'size' = TotalSize, offset = Offset, filename = RelPath}} = Async) when Offset + Block >= TotalSize ->
+  wf:info(?MODULE, "Proc Stop ~p, last piece size: ~p", [FTP#ftp{data = <<>>}, erlang:byte_size(Data)]),
+  case file:write_file(filename:join(?ROOT, RelPath), <<Data/binary>>, [append, raw]) of
+    {error, Reason} ->
+      wf:error(?MODULE, "WRITE FILE ERROR: ~p~n~p", [filename:join(?ROOT, RelPath), Reason]),
+      {reply, {error, Reason}, Async};
+    ok ->
+      wf:info(?MODULE, "WRITE FILE OK: ~p~n", [filename:join(?ROOT, RelPath)]),
+      FTP2 = FTP#ftp{data = <<>>, block = ?STOP},
+      wf:send(Sid, FTP2#ftp{status = {event, stop}, filename = RelPath}),
+      erlang:spawn(
+        fun() ->
+          n4u_async:stop(file, Link)
+        end),
+      {stop, normal, FTP2, Async#handler{state = FTP2}}
+  end;
+
+
+proc(#ftp{sid = _Sid, data = Data, block = Block} = FTP,
+     #handler{state = #ftp{data = _State, offset = Offset, filename = RelPath}} = Async) ->
+  FTP2 = FTP#ftp{status = <<"send">>, offset = Offset + Block},
+  wf:info(?MODULE, "Proc Process ~p", [FTP2#ftp{data = <<>>}]),
+  case file:write_file(filename:join(?ROOT, RelPath), <<Data/binary>>, [append, raw]) of
+    {error, Reason} ->
+      wf:error(?MODULE, "WRITE FILE ERROR 0: ~p~n~p", [filename:join(?ROOT, RelPath), Reason]),
+      {reply, {error, Reason}, Async};
+    ok ->
+      {reply, FTP2#ftp{data = <<>>}, Async#handler{state = FTP2#ftp{filename = RelPath}}}
+  end.
+