porttest.erl 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. -module(porttest).
  2. -behavior(gen_server).
  3. -export([
  4. hello/0,
  5. factorial/1
  6. ]).
  7. -export([
  8. start_link/0,
  9. stop/0
  10. ]).
  11. -export([
  12. init/1,
  13. handle_call/3,
  14. handle_cast/2,
  15. terminate/2
  16. ]).
  17. -record(state, {port}).
  18. start_link() ->
  19. gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
  20. stop() ->
  21. gen_server:call(?MODULE, stop).
  22. hello() ->
  23. gen_server:call(?MODULE, hello).
  24. factorial(N) when is_integer(N), N >= 0 ->
  25. case gen_server:call(?MODULE, {factorial, N}) of
  26. {ok, Result} when is_integer(Result) -> Result;
  27. {error, _} = Error -> Error
  28. end;
  29. factorial(_) ->
  30. {error, badarg}.
  31. %% helper
  32. parse_result("error:" ++ Rest) ->
  33. {error, list_to_binary(Rest)};
  34. parse_result(Str) ->
  35. case string:to_integer(Str) of
  36. {Int, []} -> {ok, Int};
  37. _ -> {error, badarg}
  38. end.
  39. init([]) ->
  40. Path = "./porttest", %% compiled zig program
  41. Port = open_port({spawn, Path}, [binary, exit_status]),
  42. {ok, #state{port = Port}}.
  43. handle_call(hello, _From, State) ->
  44. Port = State#state.port,
  45. Cmd = <<"hello">>,
  46. port_command(Port, <<(byte_size(Cmd)):16, Cmd/binary>>),
  47. receive
  48. {Port, {data, <<_Len:16, Resp/binary>>}} ->
  49. {reply, binary_to_list(Resp), State}
  50. after 5000 ->
  51. {reply, {error, timeout}, State}
  52. end;
  53. handle_call({factorial, N}, _From, State) ->
  54. Port = State#state.port,
  55. BinCmd = <<"factorial ", (integer_to_binary(N))/binary>>,
  56. port_command(Port, <<(byte_size(BinCmd)):16, BinCmd/binary>>),
  57. receive
  58. {Port, {data, <<_Len:16, Resp/binary>>}} ->
  59. Reply = parse_result( binary_to_list(Resp) ),
  60. {reply, Reply, State}
  61. after 5000 ->
  62. {reply, {error, timeout}, State}
  63. end;
  64. handle_call(stop, _From, State) ->
  65. Port = State#state.port,
  66. port_close(Port),
  67. {stop, normal, ok, State}.
  68. handle_cast(_Msg, State) ->
  69. {noreply, State}.
  70. terminate(_Reason, _State) ->
  71. ok.