Merge branch 'ei' into develop

This commit is contained in:
Jordan Bracco 2020-05-13 22:09:54 +02:00
commit a1236b7ea7
4 changed files with 94 additions and 37 deletions

View file

@ -2,6 +2,16 @@ defmodule GenMagic.Pool do
@behaviour NimblePool @behaviour NimblePool
@moduledoc "Pool of `GenMagic.Server`" @moduledoc "Pool of `GenMagic.Server`"
def child_spec(opts) do
%{
id: __MODULE__,
start: {__MODULE__, :start_link, [opts]},
type: :worker,
restart: :permanent,
shutdown: 500
}
end
def start_link(options, pool_size \\ nil) do def start_link(options, pool_size \\ nil) do
pool_size = pool_size || System.schedulers_online() pool_size = pool_size || System.schedulers_online()
NimblePool.start_link(worker: {__MODULE__, options}, pool_size: pool_size) NimblePool.start_link(worker: {__MODULE__, options}, pool_size: pool_size)

View file

@ -211,6 +211,7 @@ defmodule GenMagic.Server do
@doc false @doc false
def available({:call, from}, {:perform, path}, data) do def available({:call, from}, {:perform, path}, data) do
data = %{data | cycles: data.cycles + 1, request: {path, from, :erlang.now()}} data = %{data | cycles: data.cycles + 1, request: {path, from, :erlang.now()}}
send(data.port, {:file, path}) send(data.port, {:file, path})
{:next_state, :processing, data} {:next_state, :processing, data}
end end

View file

@ -68,7 +68,9 @@ void setup_system();
int process_command(byte *buf); int process_command(byte *buf);
void process_line(char *line); void process_line(char *line);
void process_file(char *path, ei_x_buff *result); void process_file(char *path, ei_x_buff *result);
void process_bytes(char *bytes, int size, ei_x_buff *result);
void error(ei_x_buff *result, const char *error); void error(ei_x_buff *result, const char *error);
void handle_magic_error(magic_t handle, int errn, ei_x_buff *result);
struct magic_file { struct magic_file {
struct magic_file *prev; struct magic_file *prev;
@ -105,7 +107,7 @@ int main(int argc, char **argv) {
int process_command(byte *buf) { int process_command(byte *buf) {
ei_x_buff result; ei_x_buff result;
char atom[128]; char atom[128];
int index, version, arity; int index, version, arity, termtype, termsize;
index = 0; index = 0;
if (ei_decode_version(buf, &index, &version) != 0) if (ei_decode_version(buf, &index, &version) != 0)
@ -130,25 +132,35 @@ int process_command(byte *buf) {
return 1; return 1;
} }
if (strncmp(atom, "file", 3) == 0) { if (strncmp(atom, "file", 4) == 0) {
int pathtype;
int pathsize;
char path[4097]; char path[4097];
ei_get_type(buf, &index, &pathtype, &pathsize); ei_get_type(buf, &index, &termtype, &termsize);
if (pathtype == ERL_BINARY_EXT && pathsize < 4096) { if (termtype == ERL_BINARY_EXT && termsize < 4096) {
long bin_length; long bin_length;
ei_decode_binary(buf, &index, path, &bin_length); ei_decode_binary(buf, &index, path, &bin_length);
path[pathsize] = '\0'; path[termsize] = '\0';
process_file(path, &result); process_file(path, &result);
} else { } else {
error(&result, "badarg"); error(&result, "badarg");
return 1; return 1;
} }
} else if (strncmp(atom, "bytes", 3) == 0) { } else if (strncmp(atom, "bytes", 5) == 0) {
ei_x_encode_atom(&result, "ok"); int termtype;
ei_x_encode_atom(&result, "bytes_not_implemented"); int termsize;
} else if (strncmp(atom, "stop", 3) == 0) { char bytes[51];
ei_get_type(buf, &index, &termtype, &termsize);
if (termtype == ERL_BINARY_EXT && termsize < 50) {
long bin_length;
ei_decode_binary(buf, &index, bytes, &bin_length);
bytes[termsize] = '\0';
process_bytes(bytes, termsize, &result);
} else {
error(&result, "badarg");
return 1;
}
} else if (strncmp(atom, "stop", 4) == 0) {
exit(ERROR_OK); exit(ERROR_OK);
} else { } else {
error(&result, "badarg"); error(&result, "badarg");
@ -249,44 +261,72 @@ magic_t magic_setup(int flags) {
return magic; return magic;
} }
void process_file(char *path, ei_x_buff *result) { void process_bytes(char *path, int size, ei_x_buff *result) {
const char *mime_type_result = magic_file(magic_mime_type, path); const char *mime_type_result = magic_buffer(magic_mime_type, path, size);
const char *mime_type_error = magic_error(magic_mime_type); const int mime_type_errno = magic_errno(magic_mime_type);
int mime_type_errno = magic_errno(magic_mime_type);
if (mime_type_errno > 0) { if (mime_type_errno > 0) {
handle_magic_error(magic_mime_type, mime_type_errno, result);
return;
}
const char *mime_encoding_result = magic_buffer(magic_mime_encoding, path, size);
int mime_encoding_errno = magic_errno(magic_mime_encoding);
if (mime_encoding_errno > 0) {
handle_magic_error(magic_mime_encoding, mime_encoding_errno, result);
return;
}
const char *type_name_result = magic_buffer(magic_type_name, path, size);
int type_name_errno = magic_errno(magic_type_name);
if (type_name_errno > 0) {
handle_magic_error(magic_type_name, type_name_errno, result);
return;
}
ei_x_encode_atom(result, "ok");
ei_x_encode_tuple_header(result, 3);
ei_x_encode_binary(result, mime_type_result, strlen(mime_type_result));
ei_x_encode_binary(result, mime_encoding_result,
strlen(mime_encoding_result));
ei_x_encode_binary(result, type_name_result, strlen(type_name_result));
return;
}
void handle_magic_error(magic_t handle, int errn, ei_x_buff *result) {
const char *error = magic_error(handle);
ei_x_encode_atom(result, "error"); ei_x_encode_atom(result, "error");
ei_x_encode_tuple_header(result, 2); ei_x_encode_tuple_header(result, 2);
long errlon = (long)mime_type_errno; long errlon = (long)errn;
ei_x_encode_long(result, errlon); ei_x_encode_long(result, errlon);
ei_x_encode_binary(result, mime_type_error, strlen(mime_type_error)); ei_x_encode_binary(result, error, strlen(error));
return;
}
void process_file(char *path, ei_x_buff *result) {
const char *mime_type_result = magic_file(magic_mime_type, path);
const int mime_type_errno = magic_errno(magic_mime_type);
if (mime_type_errno > 0) {
handle_magic_error(magic_mime_type, mime_type_errno, result);
return; return;
} }
const char *mime_encoding_result = magic_file(magic_mime_encoding, path); const char *mime_encoding_result = magic_file(magic_mime_encoding, path);
const char *mime_encoding_error = magic_error(magic_mime_encoding);
int mime_encoding_errno = magic_errno(magic_mime_encoding); int mime_encoding_errno = magic_errno(magic_mime_encoding);
if (mime_encoding_error) { if (mime_encoding_errno > 0) {
ei_x_encode_atom(result, "error"); handle_magic_error(magic_mime_encoding, mime_encoding_errno, result);
ei_x_encode_tuple_header(result, 2);
long errlon = (long)mime_encoding_errno;
ei_x_encode_long(result, errlon);
ei_x_encode_binary(result, mime_encoding_error,
strlen(mime_encoding_error));
return; return;
} }
const char *type_name_result = magic_file(magic_type_name, path); const char *type_name_result = magic_file(magic_type_name, path);
const char *type_name_error = magic_error(magic_type_name);
int type_name_errno = magic_errno(magic_type_name); int type_name_errno = magic_errno(magic_type_name);
if (type_name_error) { if (type_name_errno > 0) {
ei_x_encode_atom(result, "error"); handle_magic_error(magic_type_name, type_name_errno, result);
ei_x_encode_tuple_header(result, 2);
long errlon = (long)type_name_errno;
ei_x_encode_long(result, errlon);
ei_x_encode_binary(result, type_name_error, strlen(type_name_error));
return; return;
} }

View file

@ -66,19 +66,25 @@ defmodule GenMagic.ApprenticeTest do
refute_receive _ refute_receive _
end end
test "works", %{port: port} do test "file works", %{port: port} do
send(port, {self(), {:command, :erlang.term_to_binary({:file, Path.expand("Makefile")})}}) send(port, {self(), {:command, :erlang.term_to_binary({:file, Path.expand("Makefile")})}})
assert_receive {^port, {:data, data}} assert_receive {^port, {:data, data}}
assert {:ok, _} = :erlang.binary_to_term(data) assert {:ok, _} = :erlang.binary_to_term(data)
end end
test "bytes works", %{port: port} do
send(port, {self(), {:command, :erlang.term_to_binary({:bytes, "some bytes!"})}})
assert_receive {^port, {:data, data}}
assert {:ok, _} = :erlang.binary_to_term(data)
end
test "fails with non existent file", %{port: port} do test "fails with non existent file", %{port: port} do
send(port, {self(), {:command, :erlang.term_to_binary({:file, "/path/to/nowhere"})}}) send(port, {self(), {:command, :erlang.term_to_binary({:file, "/path/to/nowhere"})}})
assert_receive {^port, {:data, data}} assert_receive {^port, {:data, data}}
assert {:error, _} = :erlang.binary_to_term(data) assert {:error, _} = :erlang.binary_to_term(data)
end end
test "works with big path", %{port: port} do test "works with big file path", %{port: port} do
file = too_big() <> "/a" file = too_big() <> "/a"
File.mkdir_p!(too_big()) File.mkdir_p!(too_big())
File.touch!(file) File.touch!(file)