Merge branch 'ei' into develop
This commit is contained in:
commit
a1236b7ea7
4 changed files with 94 additions and 37 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
104
src/apprentice.c
104
src/apprentice.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue