agoo 2.7.0 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of agoo might be problematic. Click here for more details.

data/ext/agoo/graphql.h CHANGED
@@ -14,15 +14,16 @@
14
14
 
15
15
  typedef enum {
16
16
  GQL_UNDEF = (int8_t)0, // not defined yet
17
- GQL_OBJECT = (int8_t)1,
18
- GQL_FRAG = (int8_t)2,
19
- GQL_INPUT = (int8_t)3,
20
- GQL_UNION = (int8_t)4,
21
- GQL_INTERFACE = (int8_t)5,
22
- GQL_ENUM = (int8_t)6,
23
- GQL_SCALAR = (int8_t)7,
24
- GQL_LIST = (int8_t)8,
25
- GQL_NON_NULL = (int8_t)9,
17
+ GQL_SCHEMA = (int8_t)1,
18
+ GQL_OBJECT = (int8_t)2,
19
+ GQL_FRAG = (int8_t)3,
20
+ GQL_INPUT = (int8_t)4,
21
+ GQL_UNION = (int8_t)5,
22
+ GQL_INTERFACE = (int8_t)6,
23
+ GQL_ENUM = (int8_t)7,
24
+ GQL_SCALAR = (int8_t)8,
25
+ GQL_LIST = (int8_t)9,
26
+ GQL_NON_NULL = (int8_t)10,
26
27
  } gqlKind;
27
28
 
28
29
  typedef enum {
@@ -37,8 +38,9 @@ typedef enum {
37
38
  GQL_SCALAR_VAR = (int8_t)8,
38
39
  GQL_SCALAR_TIME = (int8_t)9,
39
40
  GQL_SCALAR_UUID = (int8_t)10,
40
- GQL_SCALAR_LIST = (int8_t)11,
41
- GQL_SCALAR_OBJECT = (int8_t)12,
41
+ GQL_SCALAR_ID = (int8_t)11,
42
+ GQL_SCALAR_LIST = (int8_t)12,
43
+ GQL_SCALAR_OBJECT = (int8_t)13,
42
44
  } gqlScalarKind;
43
45
 
44
46
  typedef enum {
@@ -125,7 +127,7 @@ typedef struct _gqlType {
125
127
  gqlScalarKind scalar_kind;
126
128
  bool core;
127
129
  union {
128
- struct { // Objects and interfaces
130
+ struct { // Schema (just fields), Objects and Interfaces
129
131
  gqlField fields;
130
132
  gqlTypeLink interfaces; // Types
131
133
  };
@@ -206,9 +208,11 @@ typedef struct _gqlDoc {
206
208
  extern int gql_init(agooErr err);
207
209
  extern void gql_destroy(); // clear out all
208
210
 
211
+ extern gqlType gql_schema_create(agooErr err, const char *desc, size_t dlen);
209
212
  extern gqlType gql_type_create(agooErr err, const char *name, const char *desc, size_t dlen, gqlTypeLink interfaces);
210
213
  extern gqlType gql_assure_type(agooErr err, const char *name);
211
- extern void gql_type_directive_use(gqlType type, gqlDirUse use);
214
+ extern int gql_type_directive_use(agooErr err, gqlType type, gqlDirUse use);
215
+ extern bool gql_type_has_directive_use(gqlType type, const char *dir);
212
216
 
213
217
  extern gqlType gql_input_create(agooErr err, const char *name, const char *desc, size_t dlen);
214
218
  extern gqlType gql_interface_create(agooErr err, const char *name, const char *desc, size_t dlen);
data/ext/agoo/log.c CHANGED
@@ -62,7 +62,9 @@ struct _agooLogCat agoo_push_cat;
62
62
  agooColor
63
63
  find_color(const char *name) {
64
64
  if (NULL != name) {
65
- for (agooColor c = colors; NULL != c->name; c++) {
65
+ agooColor c;
66
+
67
+ for (c = colors; NULL != c->name; c++) {
66
68
  if (0 == strcasecmp(c->name, name)) {
67
69
  return c;
68
70
  }
@@ -98,7 +100,7 @@ agoo_log_listen() {
98
100
  }
99
101
  }
100
102
  atomic_store(&agoo_log.wait_state, WAITING);
101
-
103
+
102
104
  return agoo_log.rsock;
103
105
  }
104
106
 
@@ -116,6 +118,7 @@ static agooLogEntry
116
118
  agoo_log_queue_pop(double timeout) {
117
119
  agooLogEntry e = atomic_load(&agoo_log.head);
118
120
  agooLogEntry next;
121
+ int cnt;
119
122
 
120
123
  if (e->ready) {
121
124
  return e;
@@ -125,7 +128,7 @@ agoo_log_queue_pop(double timeout) {
125
128
  next = agoo_log.q;
126
129
  }
127
130
  // If the next is the tail then wait for something to be appended.
128
- for (int cnt = (int)(timeout / (double)WAIT_MSECS * 1000.0); atomic_load(&agoo_log.tail) == next; cnt--) {
131
+ for (cnt = (int)(timeout / (double)WAIT_MSECS * 1000.0); atomic_load(&agoo_log.tail) == next; cnt--) {
129
132
  struct pollfd pa;
130
133
 
131
134
  if (cnt <= 0) {
@@ -176,7 +179,7 @@ classic_write(agooLogEntry e, FILE *file) {
176
179
  long long frac = (long long)e->when % 1000000000LL;
177
180
  char levelc = level_chars[e->cat->level];
178
181
  int cnt = 0;
179
-
182
+
180
183
  t += agoo_log.zone;
181
184
  if (agoo_log.day_start <= t && t < agoo_log.day_end) {
182
185
  t -= agoo_log.day_start;
@@ -271,6 +274,7 @@ void
271
274
  agoo_log_rotate() {
272
275
  char from[1060];
273
276
  char to[1060];
277
+ int seq;
274
278
 
275
279
  if (NULL != agoo_log.file) {
276
280
  fclose(agoo_log.file);
@@ -280,7 +284,7 @@ agoo_log_rotate() {
280
284
  char name[32];
281
285
 
282
286
  sprintf(name, "%s_%d.log", agoo_log.app, getpid());
283
- for (int seq = agoo_log.max_files; 0 < seq; seq--) {
287
+ for (seq = agoo_log.max_files; 0 < seq; seq--) {
284
288
  snprintf(to, sizeof(to) - 1, "%s/%s_%d.log.%d", agoo_log.dir, agoo_log.app, getpid(), seq + 1);
285
289
  snprintf(from, sizeof(from) - 1, "%s/%s_%d.log.%d", agoo_log.dir, agoo_log.app, getpid(), seq);
286
290
  rename(from, to);
@@ -288,7 +292,7 @@ agoo_log_rotate() {
288
292
  snprintf(to, sizeof(to) - 1, "%s/%s_%d.log.%d", agoo_log.dir, agoo_log.app, getpid(), 1);
289
293
  snprintf(from, sizeof(from) - 1, "%s/%s", agoo_log.dir, name);
290
294
  } else {
291
- for (int seq = agoo_log.max_files; 0 < seq; seq--) {
295
+ for (seq = agoo_log.max_files; 0 < seq; seq--) {
292
296
  snprintf(to, sizeof(to) - 1, "%s/%s.log.%d", agoo_log.dir, agoo_log.app, seq + 1);
293
297
  snprintf(from, sizeof(from) - 1, "%s/%s.log.%d", agoo_log.dir, agoo_log.app, seq);
294
298
  rename(from, to);
@@ -338,7 +342,7 @@ loop(void *ctx) {
338
342
  bool
339
343
  agoo_log_flush(double timeout) {
340
344
  timeout += dtime();
341
-
345
+
342
346
  while (!agoo_log.done && !agoo_log_queue_empty()) {
343
347
  if (timeout < dtime()) {
344
348
  return false;
@@ -405,7 +409,7 @@ agoo_log_close() {
405
409
  void
406
410
  agoo_log_cat_reg(agooLogCat cat, const char *label, agooLogLevel level, const char *color, bool on) {
407
411
  agooLogCat xcat = agoo_log_cat_find(label);
408
-
412
+
409
413
  if (NULL != xcat) {
410
414
  cat = xcat;
411
415
  }
@@ -448,7 +452,7 @@ agoo_log_cat_find(const char *label) {
448
452
  int64_t
449
453
  agoo_now_nano() {
450
454
  struct timespec ts;
451
-
455
+
452
456
  clock_gettime(CLOCK_REALTIME, &ts);
453
457
 
454
458
  return (int64_t)ts.tv_sec * 1000000000LL + (int64_t)ts.tv_nsec;
@@ -502,13 +506,13 @@ agoo_log_catv(agooLogCat cat, const char *tid, const char *fmt, va_list ap) {
502
506
  if (cat->on && !agoo_log.done) {
503
507
  agooLogEntry e;
504
508
  agooLogEntry tail;
505
-
509
+
506
510
  while (atomic_flag_test_and_set(&agoo_log.push_lock)) {
507
511
  dsleep(RETRY_SECS);
508
512
  }
509
513
  if (0 == agoo_log.thread) {
510
514
  struct _agooLogEntry entry;
511
-
515
+
512
516
  set_entry(&entry, cat, tid, fmt, ap);
513
517
  if (agoo_log.classic) {
514
518
  classic_write(&entry, stdout);
@@ -560,7 +564,7 @@ agoo_log_tid_cat(agooLogCat cat, const char *tid, const char *fmt, ...) {
560
564
  int
561
565
  agoo_log_start(agooErr err, bool with_pid) {
562
566
  int stat;
563
-
567
+
564
568
  if (0 != agoo_log.thread) {
565
569
  // Already started.
566
570
  return AGOO_ERR_OK;
@@ -17,7 +17,7 @@ rack_logger_new() {
17
17
  static void
18
18
  log_message(agooLogCat cat, VALUE message) {
19
19
  volatile VALUE rs = rb_funcall(message, rb_intern("to_s"), 0);
20
-
20
+
21
21
  rb_check_type(rs, T_STRING);
22
22
  if (!agoo_server.active) {
23
23
  return;
@@ -31,6 +31,9 @@ log_message(agooLogCat cat, VALUE message) {
31
31
  text = agoo_text_append(text, ": ", 2);
32
32
  text = agoo_text_append(text, StringValuePtr(rs), (int)RSTRING_LEN(rs));
33
33
  }
34
+ if (NULL == text) {
35
+ rb_raise(rb_eNoMemError, "Failed to allocate memory for a log message.");
36
+ }
34
37
  agoo_log_cat(cat, "%s", text->text);
35
38
  agoo_text_release(text);
36
39
  } else {
data/ext/agoo/request.c CHANGED
@@ -359,7 +359,6 @@ rack_run_once(VALUE self) {
359
359
  return Qfalse;
360
360
  }
361
361
 
362
- // TBD req.c
363
362
  static void
364
363
  add_header_value(VALUE hh, const char *key, int klen, const char *val, int vlen) {
365
364
  if (sizeof(content_type) - 1 == klen && 0 == strncasecmp(key, content_type, sizeof(content_type) - 1)) {
@@ -370,7 +369,7 @@ add_header_value(VALUE hh, const char *key, int klen, const char *val, int vlen)
370
369
  char hkey[1024];
371
370
  char *k = hkey;
372
371
  volatile VALUE sval = rb_str_new(val, vlen);
373
-
372
+
374
373
  strcpy(hkey, "HTTP_");
375
374
  k = hkey + 5;
376
375
  if ((int)(sizeof(hkey) - 5) <= klen) {
@@ -378,7 +377,7 @@ add_header_value(VALUE hh, const char *key, int klen, const char *val, int vlen)
378
377
  }
379
378
  strncpy(k, key, klen);
380
379
  hkey[klen + 5] = '\0';
381
-
380
+
382
381
  //rb_hash_aset(hh, rb_str_new(hkey, klen + 5), sval);
383
382
  // Contrary to the Rack spec, Rails expects all upper case keys so add those as well.
384
383
  for (k = hkey + 5; '\0' != *k; k++) {
@@ -392,7 +391,6 @@ add_header_value(VALUE hh, const char *key, int klen, const char *val, int vlen)
392
391
  }
393
392
  }
394
393
 
395
- // TBD req.c
396
394
  static void
397
395
  fill_headers(agooReq r, VALUE hash) {
398
396
  char *h = r->header.start;
@@ -408,7 +406,7 @@ fill_headers(agooReq r, VALUE hash) {
408
406
  if (NULL == r) {
409
407
  rb_raise(rb_eArgError, "Request is no longer valid.");
410
408
  }
411
-
409
+
412
410
  for (; h < end; h++) {
413
411
  switch (*h) {
414
412
  case ':':
@@ -533,7 +531,7 @@ VALUE
533
531
  request_env(agooReq req, VALUE self) {
534
532
  if (Qnil == (VALUE)req->env) {
535
533
  volatile VALUE env = rb_hash_new();
536
-
534
+
537
535
  // As described by
538
536
  // http://www.rubydoc.info/github/rack/rack/master/file/SPEC and
539
537
  // https://github.com/rack/rack/blob/master/SPEC.
@@ -625,7 +623,7 @@ call(VALUE self) {
625
623
 
626
624
  io = rb_class_new_instance(1, args, rb_cIO);
627
625
  rb_hash_aset((VALUE)r->env, rack_hijack_io_val, io);
628
-
626
+
629
627
  return io;
630
628
  }
631
629
 
@@ -669,12 +667,12 @@ request_init(VALUE mod) {
669
667
  rb_define_method(req_class, "call", call, 0);
670
668
 
671
669
  new_id = rb_intern("new");
672
-
670
+
673
671
  rack_version_val_val = rb_ary_new();
674
672
  rb_ary_push(rack_version_val_val, INT2NUM(1));
675
673
  rb_ary_push(rack_version_val_val, INT2NUM(3));
676
674
  rb_gc_register_address(&rack_version_val_val);
677
-
675
+
678
676
  stringio_class = rb_const_get(rb_cObject, rb_intern("StringIO"));
679
677
 
680
678
  connect_val = rb_str_new_cstr("CONNECT"); rb_gc_register_address(&connect_val);
data/ext/agoo/rgraphql.c CHANGED
@@ -31,7 +31,7 @@ static VALUE vroot = Qnil;
31
31
  static TypeClass type_class_map = NULL;
32
32
 
33
33
  static int
34
- make_ruby_use(agooErr err, VALUE root, const char *method, const char *type_name) {
34
+ make_ruby_use(agooErr err, VALUE root, const char *method, const char *type_name, bool fresh, gqlType schema_type, const char *desc) {
35
35
  gqlType type;
36
36
  gqlDirUse use;
37
37
  volatile VALUE v;
@@ -44,14 +44,18 @@ make_ruby_use(agooErr err, VALUE root, const char *method, const char *type_name
44
44
  if (NULL == (type = gql_type_get(type_name))) {
45
45
  return agoo_err_set(err, AGOO_ERR_ARG, "Failed to find the '%s' type.", type_name);
46
46
  }
47
- if (NULL == (use = gql_dir_use_create(err, "ruby"))) {
48
- return err->code;
47
+ if (fresh) {
48
+ if (NULL == gql_type_field(err, schema_type, method, type, NULL, desc, 0, false)) {
49
+ return err->code;
50
+ }
49
51
  }
50
- if (AGOO_ERR_OK != gql_dir_use_arg(err, use, "class", gql_string_create(err, rb_obj_classname(v), 0))) {
51
- return err->code;
52
+ if (!gql_type_has_directive_use(type, "ruby")) {
53
+ if (NULL == (use = gql_dir_use_create(err, "ruby")) ||
54
+ AGOO_ERR_OK != gql_dir_use_arg(err, use, "class", gql_string_create(err, rb_obj_classname(v), 0)) ||
55
+ AGOO_ERR_OK != gql_type_directive_use(err, type, use)) {
56
+ return err->code;
57
+ }
52
58
  }
53
- gql_type_directive_use(type, use);
54
-
55
59
  return AGOO_ERR_OK;
56
60
  }
57
61
 
@@ -120,6 +124,7 @@ gval_to_ruby(gqlValue value) {
120
124
  break;
121
125
  case GQL_SCALAR_STRING:
122
126
  case GQL_SCALAR_TOKEN:
127
+ case GQL_SCALAR_ID:
123
128
  rval = rb_str_new_cstr(gql_string_get(value));
124
129
  break;
125
130
  case GQL_SCALAR_TIME: {
@@ -290,6 +295,7 @@ coerce(agooErr err, gqlRef ref, gqlType type) {
290
295
  break;
291
296
  case GQL_SCALAR_STRING:
292
297
  case GQL_SCALAR_TOKEN:
298
+ case GQL_SCALAR_ID:
293
299
  v = ref_to_string(ref);
294
300
  value = gql_string_create(err, rb_string_value_ptr(&v), RSTRING_LEN(v));
295
301
  break;
@@ -559,29 +565,30 @@ rescue_yield(VALUE x) {
559
565
  static VALUE
560
566
  graphql_schema(VALUE self, VALUE root) {
561
567
  struct _agooErr err = AGOO_ERR_INIT;
562
- gqlType type;
563
568
  gqlDir dir;
564
569
  gqlDirUse use;
570
+ gqlType schema_type;
571
+ bool fresh = false;
565
572
 
566
573
  if (!rb_block_given_p()) {
567
574
  rb_raise(rb_eStandardError, "A block is required.");
568
575
  }
569
576
  if (AGOO_ERR_OK != gql_init(&err)) {
570
577
  printf("*-*-* %s\n", err.msg);
571
- exit(0);
578
+ exit(1);
572
579
  }
573
580
  if (NULL == (dir = gql_directive_create(&err, "ruby", "Associates a Ruby class with a GraphQL type.", 0))) {
574
581
  printf("*-*-* %s\n", err.msg);
575
- exit(0);
582
+ exit(2);
576
583
  }
577
584
  if (NULL == gql_dir_arg(&err, dir, "class", &gql_string_type, NULL, 0, NULL, true)) {
578
585
  printf("*-*-* %s\n", err.msg);
579
- exit(0);
586
+ exit(3);
580
587
  }
581
588
  if (AGOO_ERR_OK != gql_directive_on(&err, dir, "SCHEMA", 6) ||
582
589
  AGOO_ERR_OK != gql_directive_on(&err, dir, "OBJECT", 6)) {
583
590
  printf("*-*-* %s\n", err.msg);
584
- exit(0);
591
+ exit(4);
585
592
  }
586
593
  gql_root = (gqlRef)root;
587
594
  vroot = root;
@@ -594,33 +601,36 @@ graphql_schema(VALUE self, VALUE root) {
594
601
 
595
602
  if (NULL == (use = gql_dir_use_create(&err, "ruby"))) {
596
603
  printf("*-*-* %s\n", err.msg);
597
- exit(0);
604
+ exit(5);
598
605
  }
599
606
  if (AGOO_ERR_OK != gql_dir_use_arg(&err, use, "class", gql_string_create(&err, rb_obj_classname(root), 0))) {
600
607
  printf("*-*-* %s\n", err.msg);
601
- exit(0);
602
- }
603
- if (NULL == (type = gql_type_get("schema"))) {
604
- printf("*-*-* Error: Failed to find the 'schema' type.");
605
- exit(0);
606
- }
607
- gql_type_directive_use(type, use);
608
-
609
- if (AGOO_ERR_OK != make_ruby_use(&err, root, "query", "Query") ||
610
- AGOO_ERR_OK != make_ruby_use(&err, root, "mutation", "Mutation") ||
611
- AGOO_ERR_OK != make_ruby_use(&err, root, "subscription", "Subscription")) {
612
- printf("*-*-* %s\n", err.msg);
613
- exit(0);
608
+ exit(6);
614
609
  }
615
610
  rb_rescue2(rescue_yield, Qnil, rescue_yield_error, (VALUE)&err, rb_eException, 0);
616
611
  if (AGOO_ERR_OK != err.code) {
617
612
  printf("*-*-* %s\n", err.msg);
618
- exit(0);
613
+ exit(7);
614
+ }
615
+ if (NULL == (schema_type = gql_type_get("schema"))) {
616
+ if (NULL == (schema_type = gql_schema_create(&err, "The GraphQL root Object.", 0))) {
617
+ printf("*-*-* %s\n", err.msg);
618
+ exit(8);
619
+ }
620
+ fresh = true;
621
+ }
622
+
623
+ if (AGOO_ERR_OK != gql_type_directive_use(&err, schema_type, use) ||
624
+ AGOO_ERR_OK != make_ruby_use(&err, root, "query", "Query", fresh, schema_type, "Root level query.") ||
625
+ AGOO_ERR_OK != make_ruby_use(&err, root, "mutation", "Mutation", fresh, schema_type, "Root level mutation.") ||
626
+ AGOO_ERR_OK != make_ruby_use(&err, root, "subscription", "Subscription", fresh, schema_type, "Root level subscription.")) {
627
+ printf("*-*-* %s\n", err.msg);
628
+ exit(9);
619
629
  }
620
630
  if (AGOO_ERR_OK != gql_validate(&err) ||
621
631
  AGOO_ERR_OK != build_type_class_map(&err)) {
622
632
  printf("*-*-* %s\n", err.msg);
623
- exit(0);
633
+ exit(10);
624
634
  }
625
635
  return Qnil;
626
636
  }
@@ -726,8 +736,9 @@ graphql_sdl_dump(VALUE self, VALUE options) {
726
736
  if (Qnil != v) {
727
737
  all = (Qtrue == v);
728
738
  }
729
- t = gql_schema_sdl(t, with_desc, all);
730
-
739
+ if (NULL == (t = gql_schema_sdl(t, with_desc, all))) {
740
+ rb_raise(rb_eNoMemError, "Failed to allocate memory for a schema dump.");
741
+ }
731
742
  dump = rb_str_new(t->text, t->len);
732
743
  agoo_text_release(t);
733
744
 
data/ext/agoo/rresponse.c CHANGED
@@ -33,7 +33,7 @@ response_new() {
33
33
  }
34
34
  memset(res, 0, sizeof(struct _agooResponse));
35
35
  res->code = 200;
36
-
36
+
37
37
  return Data_Wrap_Struct(res_class, NULL, response_free, res);
38
38
  }
39
39
 
@@ -53,7 +53,7 @@ to_s(VALUE self) {
53
53
  rb_raise(rb_eNoMemError, "out of memory");
54
54
  }
55
55
  agoo_response_fill(res, s);
56
-
56
+
57
57
  return rb_str_new(s, len);
58
58
  }
59
59
 
@@ -150,7 +150,7 @@ head_get(VALUE self, VALUE key) {
150
150
  agooHeader h;
151
151
  const char *ks = StringValuePtr(key);
152
152
  int klen = (int)RSTRING_LEN(key);
153
-
153
+
154
154
  for (h = res->headers; NULL != h; h = h->next) {
155
155
  if (0 == strncasecmp(h->text, ks, klen) && klen + 1 < h->len && ':' == h->text[klen]) {
156
156
  return rb_str_new(h->text + klen + 2, h->len - klen - 4);
@@ -227,9 +227,10 @@ response_text(VALUE self) {
227
227
  int len = agoo_response_len(res);
228
228
  agooText t = agoo_text_allocate(len);
229
229
 
230
- agoo_response_fill(res, t->text);
231
- t->len = len;
232
-
230
+ if (NULL != t) {
231
+ agoo_response_fill(res, t->text);
232
+ t->len = len;
233
+ }
233
234
  return t;
234
235
  }
235
236