Class: Agoo::Server
- Inherits:
-
Object
- Object
- Agoo::Server
- Defined in:
- ext/agoo/server.c,
ext/agoo/server.c
Overview
An HTTP server that support the rack API as well as some other optimized APIs for handling HTTP requests.
Class Method Summary collapse
-
.new(*args) ⇒ Object
call-seq: new(port, root, options).
Instance Method Summary collapse
-
#add_mime(suffix, type) ⇒ Object
call-seq: add_mime(suffix, type).
-
#debug(msg) ⇒ Object
call-seq: debug(msg).
-
#debug? ⇒ Boolean
call-seq: debug?().
-
#error(msg) ⇒ Object
call-seq: error(msg).
-
#error? ⇒ Boolean
call-seq: error?().
-
#handle(method, pattern, handler) ⇒ Object
call-seq: handle(method, pattern, handler).
-
#handle_not_found(handler) ⇒ Object
call-seq: not_found_handle(handler).
-
#info(msg) ⇒ Object
call-seq: info(msg).
-
#info? ⇒ Boolean
call-seq: info?().
-
#log_eval(msg) ⇒ Object
call-seq: log_eval(msg).
-
#log_eval? ⇒ Boolean
call-seq: eval?().
-
#log_flush(to) ⇒ Object
call-seq: log_flush().
-
#log_state(label) ⇒ Object
call-seq: log_state(label).
-
#set_log_state(label, on) ⇒ Object
call-seq: set_log_state(label, state).
-
#shutdown ⇒ Object
call-seq: shutdown().
-
#start ⇒ Object
call-seq: start().
-
#warn(msg) ⇒ Object
call-seq: warn(msg).
-
#warn? ⇒ Boolean
call-seq: warn?().
Class Method Details
.new(*args) ⇒ Object
call-seq: new(port, root, options)
Creates a new server that will listen on the designated port and using the root as the root of the static resources. Logging is feature based and not level based and the options reflect that approach.
-
options [Hash] server options
-
:pedantic [true|false] if true response header and status codes are check and an exception raised if they violate the rack spec at github.com/rack/rack/blob/master/SPEC, tools.ietf.org/html/rfc3875#section-4.1.18, or tools.ietf.org/html/rfc7230.
-
:thread_count [Integer] number of ruby worker threads. Defaults to one. If zero then the start function will not return but instead will proess using the thread that called start. Usually the default is best unless the workers are making IO calls.
-
:log_dir [String] directory to place log files in. If nil or empty then no log files are written.
-
:log_console [true|false] if true log entry are display on the console.
-
:log_classic [true|false] if true log entry follow a classic format. If false log entries are JSON.
-
:log_colorize [true|false] if true log entries are colorized.
-
:log_states [Hash] a map of logging categories and whether they should be on or off. Categories are:
-
:ERROR errors
-
:WARN warnings
-
:INFO infomational
-
:DEBUG debugging
-
:connect openning and closing of connections
-
:request requests
-
:response responses
-
:eval handler evaluationss
-
-
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'ext/agoo/server.c', line 184
static VALUE
server_new(int argc, VALUE *argv, VALUE self) {
Server s;
struct _Err err = ERR_INIT;
int port;
const char *root;
VALUE options = Qnil;
if (argc < 2 || 3 < argc) {
rb_raise(rb_eArgError, "Wrong number of arguments to Agoo::Server.new.");
}
port = FIX2INT(argv[0]);
rb_check_type(argv[1], T_STRING);
root = StringValuePtr(argv[1]);
if (3 <= argc) {
options = argv[2];
}
s = ALLOC(struct _Server);
memset(s, 0, sizeof(struct _Server));
if (ERR_OK != configure(&err, s, port, root, options)) {
xfree(s);
// TBD raise Agoo specific exception
rb_raise(rb_eArgError, "%s", err.msg);
}
queue_multi_init(&s->con_queue, 256, false, false);
queue_multi_init(&s->eval_queue, 1024, false, true);
cache_init(&s->pages);
the_server = s;
return Data_Wrap_Struct(server_class, NULL, server_free, s);
}
|
Instance Method Details
#add_mime(suffix, type) ⇒ Object
call-seq: add_mime(suffix, type)
Adds a mime type by associating a type string with a suffix. This is used for static files.
896 897 898 899 900 901 |
# File 'ext/agoo/server.c', line 896
static VALUE
add_mime(VALUE self, VALUE suffix, VALUE type) {
mime_set(&((Server)DATA_PTR(self))->pages, StringValuePtr(suffix), StringValuePtr(type));
return Qnil;
}
|
#debug(msg) ⇒ Object
call-seq: debug(msg)
Log a debug message.
743 744 745 746 747 |
# File 'ext/agoo/server.c', line 743
static VALUE
log_debug(VALUE self, VALUE msg) {
log_cat(&((Server)DATA_PTR(self))->debug_cat, "%s", StringValuePtr(msg));
return Qnil;
}
|
#debug? ⇒ Boolean
call-seq: debug?()
Returns true is debug entries are being logged.
685 686 687 688 |
# File 'ext/agoo/server.c', line 685
static VALUE
log_debugp(VALUE self) {
return ((Server)DATA_PTR(self))->debug_cat.on ? Qtrue : Qfalse;
}
|
#error(msg) ⇒ Object
call-seq: error(msg)
Log an error message.
707 708 709 710 711 |
# File 'ext/agoo/server.c', line 707
static VALUE
log_error(VALUE self, VALUE msg) {
log_cat(&((Server)DATA_PTR(self))->error_cat, "%s", StringValuePtr(msg));
return Qnil;
}
|
#error? ⇒ Boolean
call-seq: error?()
Returns true is errors are being logged.
652 653 654 655 |
# File 'ext/agoo/server.c', line 652
static VALUE
log_errorp(VALUE self) {
return ((Server)DATA_PTR(self))->error_cat.on ? Qtrue : Qfalse;
}
|
#handle(method, pattern, handler) ⇒ Object
call-seq: handle(method, pattern, handler)
Registers a handler for the HTTP method and path pattern specified. The path pattern follows glob like rules in that a single * matches a single token bounded by the ‘/` character and a double ** matches all remaining.
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 |
# File 'ext/agoo/server.c', line 822
static VALUE
handle(VALUE self, VALUE method, VALUE pattern, VALUE handler) {
Server server = (Server)DATA_PTR(self);
Hook hook;
Method meth = ALL;
const char *pat;
rb_check_type(pattern, T_STRING);
pat = StringValuePtr(pattern);
if (connect_sym == method) {
meth = CONNECT;
} else if (delete_sym == method) {
meth = DELETE;
} else if (get_sym == method) {
meth = GET;
} else if (head_sym == method) {
meth = HEAD;
} else if (options_sym == method) {
meth = OPTIONS;
} else if (post_sym == method) {
meth = POST;
} else if (put_sym == method) {
meth = PUT;
} else if (Qnil == method) {
meth = ALL;
} else {
rb_raise(rb_eArgError, "invalid method");
}
if (NULL == (hook = hook_create(meth, pat, handler))) {
rb_raise(rb_eStandardError, "out of memory.");
} else {
Hook h;
Hook prev = NULL;
for (h = server->hooks; NULL != h; h = h->next) {
prev = h;
}
if (NULL != prev) {
prev->next = hook;
} else {
server->hooks = hook;
}
rb_gc_register_address(&hook->handler);
}
return Qnil;
}
|
#handle_not_found(handler) ⇒ Object
call-seq: not_found_handle(handler)
Registers a handler to be called when no other hook is found and no static file is found.
877 878 879 880 881 882 883 884 885 886 887 |
# File 'ext/agoo/server.c', line 877
static VALUE
handle_not_found(VALUE self, VALUE handler) {
Server server = (Server)DATA_PTR(self);
if (NULL == (server->hook404 = hook_create(GET, "/", handler))) {
rb_raise(rb_eStandardError, "out of memory.");
}
rb_gc_register_address(&server->hook404->handler);
return Qnil;
}
|
#info(msg) ⇒ Object
call-seq: info(msg)
Log an info message.
731 732 733 734 735 |
# File 'ext/agoo/server.c', line 731
static VALUE
log_info(VALUE self, VALUE msg) {
log_cat(&((Server)DATA_PTR(self))->info_cat, "%s", StringValuePtr(msg));
return Qnil;
}
|
#info? ⇒ Boolean
call-seq: info?()
Returns true is info entries are being logged.
674 675 676 677 |
# File 'ext/agoo/server.c', line 674
static VALUE
log_infop(VALUE self) {
return ((Server)DATA_PTR(self))->info_cat.on ? Qtrue : Qfalse;
}
|
#log_eval(msg) ⇒ Object
call-seq: log_eval(msg)
Log an eval message.
755 756 757 758 759 |
# File 'ext/agoo/server.c', line 755
static VALUE
log_eval(VALUE self, VALUE msg) {
log_cat(&((Server)DATA_PTR(self))->eval_cat, "%s", StringValuePtr(msg));
return Qnil;
}
|
#log_eval? ⇒ Boolean
call-seq: eval?()
Returns true is handler evaluation entries are being logged.
696 697 698 699 |
# File 'ext/agoo/server.c', line 696
static VALUE
log_evalp(VALUE self) {
return ((Server)DATA_PTR(self))->eval_cat.on ? Qtrue : Qfalse;
}
|
#log_flush(to) ⇒ Object
call-seq: log_flush()
Flush the log queue and write all entries to disk or the console. The call waits for the flush to complete.
804 805 806 807 808 809 810 811 812 |
# File 'ext/agoo/server.c', line 804
static VALUE
server_log_flush(VALUE self, VALUE to) {
double timeout = NUM2DBL(to);
if (!log_flush(&((Server)DATA_PTR(self))->log, timeout)) {
rb_raise(rb_eStandardError, "timed out waiting for log flush.");
}
return Qnil;
}
|
#log_state(label) ⇒ Object
call-seq: log_state(label)
Return the logging state of the category identified by the label.
767 768 769 770 771 772 773 774 775 776 |
# File 'ext/agoo/server.c', line 767
static VALUE
log_state(VALUE self, VALUE label) {
Server server = (Server)DATA_PTR(self);
LogCat cat = log_cat_find(&server->log, StringValuePtr(label));
if (NULL == cat) {
rb_raise(rb_eArgError, "%s is not a valid log category.", StringValuePtr(label));
}
return cat->on ? Qtrue : Qfalse;
}
|
#set_log_state(label, on) ⇒ Object
call-seq: set_log_state(label, state)
Set the logging state of the category identified by the label.
784 785 786 787 788 789 790 791 792 793 794 795 |
# File 'ext/agoo/server.c', line 784
static VALUE
set_log_state(VALUE self, VALUE label, VALUE on) {
Server server = (Server)DATA_PTR(self);
LogCat cat = log_cat_find(&server->log, StringValuePtr(label));
if (NULL == cat) {
rb_raise(rb_eArgError, "%s is not a valid log category.", StringValuePtr(label));
}
cat->on = (Qtrue == on);
return Qnil;
}
|
#shutdown ⇒ Object
call-seq: shutdown()
Shutdown the server. Logs and queues are flushed before shutting down.
640 641 642 643 644 |
# File 'ext/agoo/server.c', line 640
static VALUE
server_shutdown(VALUE self) {
shutdown_server((Server)DATA_PTR(self));
return Qnil;
}
|
#start ⇒ Object
call-seq: start()
Start the server.
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 |
# File 'ext/agoo/server.c', line 566
static VALUE
start(VALUE self) {
Server server = (Server)DATA_PTR(self);
VALUE *vp;
int i;
double giveup;
server->active = true;
server->ready = false;
pthread_create(&server->listen_thread, NULL, listen_loop, server);
pthread_create(&server->con_thread, NULL, con_loop, server);
giveup = dtime() + 1.0;
while (dtime() < giveup) {
if (server->ready) {
break;
}
dsleep(0.001);
}
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
signal(SIGPIPE, SIG_IGN);
if (server->info_cat.on) {
VALUE agoo = rb_const_get_at(rb_cObject, rb_intern("Agoo"));
VALUE v = rb_const_get_at(agoo, rb_intern("VERSION"));
log_cat(&server->info_cat, "Agoo %s listening on port %d.", StringValuePtr(v), server->port);
}
if (0 >= server->thread_cnt) {
Req req;
while (server->active) {
if (NULL != (req = (Req)queue_pop(&server->eval_queue, 0.1))) {
switch (req->handler_type) {
case BASE_HOOK:
handle_base(req);
break;
case RACK_HOOK:
handle_rack(req);
break;
case WAB_HOOK:
handle_wab(req);
break;
default: {
char buf[256];
int cnt = snprintf(buf, sizeof(buf), "HTTP/1.1 500 Internal Error\r\nConnection: Close\r\nContent-Length: 0\r\n\r\n");
Text message = text_create(buf, cnt);
req->res->close = true;
res_set_message(req->res, message);
queue_wakeup(&req->server->con_queue);
break;
}
}
}
}
} else {
server->eval_threads = ALLOC_N(VALUE, server->thread_cnt + 1);
for (i = server->thread_cnt, vp = server->eval_threads; 0 < i; i--, vp++) {
*vp = rb_thread_create(wrap_process_loop, server);
}
*vp = Qnil;
}
return Qnil;
}
|
#warn(msg) ⇒ Object
call-seq: warn(msg)
Log a warn message.
719 720 721 722 723 |
# File 'ext/agoo/server.c', line 719
static VALUE
log_warn(VALUE self, VALUE msg) {
log_cat(&((Server)DATA_PTR(self))->warn_cat, "%s", StringValuePtr(msg));
return Qnil;
}
|
#warn? ⇒ Boolean
call-seq: warn?()
Returns true is warnings are being logged.
663 664 665 666 |
# File 'ext/agoo/server.c', line 663
static VALUE
log_warnp(VALUE self) {
return ((Server)DATA_PTR(self))->warn_cat.on ? Qtrue : Qfalse;
}
|