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/rserver.c CHANGED
@@ -11,6 +11,7 @@
11
11
  #include <ruby/thread.h>
12
12
  #include <ruby/encoding.h>
13
13
 
14
+ #include "atomic.h"
14
15
  #include "bind.h"
15
16
  #include "con.h"
16
17
  #include "debug.h"
@@ -33,7 +34,8 @@
33
34
  #include "upgraded.h"
34
35
  #include "websocket.h"
35
36
 
36
- extern void agoo_shutdown();
37
+ extern void agoo_shutdown();
38
+ extern sig_atomic_t agoo_stop;
37
39
 
38
40
  static VALUE server_mod = Qundef;
39
41
 
@@ -160,7 +162,7 @@ configure(agooErr err, int port, const char *root, VALUE options) {
160
162
  if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("bind"))))) {
161
163
  int len;
162
164
  int i;
163
-
165
+
164
166
  switch (rb_type(v)) {
165
167
  case T_STRING:
166
168
  url_bind(v);
@@ -171,7 +173,7 @@ configure(agooErr err, int port, const char *root, VALUE options) {
171
173
  url_bind(rb_ary_entry(v, i));
172
174
  }
173
175
  break;
174
- default:
176
+ default:
175
177
  rb_raise(rb_eArgError, "bind option must be a String or Array of Strings.");
176
178
  break;
177
179
  }
@@ -317,7 +319,7 @@ rescue_error(VALUE x) {
317
319
  int blen = RARRAY_LEN(bt);
318
320
  int i;
319
321
  VALUE rline;
320
-
322
+
321
323
  for (i = 0; i < blen; i++) {
322
324
  rline = rb_ary_entry(bt, i);
323
325
  }
@@ -357,7 +359,7 @@ header_cb(VALUE key, VALUE value, agooText *tp) {
357
359
  const char *vs = StringValuePtr(value);
358
360
  int vlen = (int)RSTRING_LEN(value);
359
361
  struct _agooErr err = AGOO_ERR_INIT;
360
-
362
+
361
363
  if (agoo_server.pedantic) {
362
364
  if (AGOO_ERR_OK != agoo_http_header_ok(&err, ks, klen, vs, vlen)) {
363
365
  rb_raise(rb_eArgError, "%s", err.msg);
@@ -436,7 +438,7 @@ handle_rack_inner(void *x) {
436
438
  rb_raise(rb_eArgError, "invalid rack call() response body does not respond to each.");
437
439
  }
438
440
  if (NULL == (t = agoo_text_allocate(1024))) {
439
- rb_raise(rb_eArgError, "failed to allocate response.");
441
+ rb_raise(rb_eNoMemError, "Failed to allocate memory for a response.");
440
442
  }
441
443
  if (T_ARRAY == rb_type(bv)) {
442
444
  int i;
@@ -629,7 +631,7 @@ handle_push_inner(void *x) {
629
631
  break;
630
632
  }
631
633
  agoo_upgraded_release(req->up);
632
-
634
+
633
635
  return Qfalse;
634
636
  }
635
637
 
@@ -678,8 +680,8 @@ handle_protected(agooReq req, bool gvi) {
678
680
  agoo_queue_wakeup(&agoo_server.con_queue);
679
681
  break;
680
682
  default: {
681
- char buf[256];
682
- int cnt = snprintf(buf, sizeof(buf), "HTTP/1.1 500 Internal Error\r\nConnection: Close\r\nContent-Length: 0\r\n\r\n");
683
+ char buf[256];
684
+ int cnt = snprintf(buf, sizeof(buf), "HTTP/1.1 500 Internal Error\r\nConnection: Close\r\nContent-Length: 0\r\n\r\n");
683
685
  agooText message = agoo_text_create(buf, cnt);
684
686
 
685
687
  req->res->close = true;
@@ -693,13 +695,17 @@ handle_protected(agooReq req, bool gvi) {
693
695
  static void*
694
696
  process_loop(void *ptr) {
695
697
  agooReq req;
696
-
698
+
697
699
  atomic_fetch_add(&agoo_server.running, 1);
698
700
  while (agoo_server.active) {
699
701
  if (NULL != (req = (agooReq)agoo_queue_pop(&agoo_server.eval_queue, 0.1))) {
700
702
  handle_protected(req, true);
701
703
  agoo_req_destroy(req);
702
704
  }
705
+ if (agoo_stop) {
706
+ agoo_shutdown();
707
+ break;
708
+ }
703
709
  }
704
710
  atomic_fetch_sub(&agoo_server.running, 1);
705
711
 
@@ -727,9 +733,9 @@ rserver_start(VALUE self) {
727
733
  struct _agooErr err = AGOO_ERR_INIT;
728
734
  VALUE agoo = rb_const_get_at(rb_cObject, rb_intern("Agoo"));
729
735
  VALUE v = rb_const_get_at(agoo, rb_intern("VERSION"));
730
-
736
+
731
737
  *the_rserver.worker_pids = getpid();
732
-
738
+
733
739
  // If workers then set the loop_max based on the expected number of
734
740
  // threads per worker.
735
741
  if (1 < the_rserver.worker_cnt) {
@@ -774,11 +780,15 @@ rserver_start(VALUE self) {
774
780
  } else {
775
781
  rb_thread_schedule();
776
782
  }
777
-
783
+ if (agoo_stop) {
784
+ agoo_shutdown();
785
+ break;
786
+ }
778
787
  }
779
788
  } else {
780
- the_rserver.eval_threads = (VALUE*)AGOO_MALLOC(sizeof(VALUE) * (agoo_server.thread_cnt + 1));
781
-
789
+ if (NULL == (the_rserver.eval_threads = (VALUE*)AGOO_MALLOC(sizeof(VALUE) * (agoo_server.thread_cnt + 1)))) {
790
+ rb_raise(rb_eNoMemError, "Failed to allocate memory for the thread pool.");
791
+ }
782
792
  for (i = agoo_server.thread_cnt, vp = the_rserver.eval_threads; 0 < i; i--, vp++) {
783
793
  *vp = rb_thread_create(wrap_process_loop, NULL);
784
794
  }
@@ -834,7 +844,7 @@ rserver_shutdown(VALUE self) {
834
844
  int status;
835
845
  int exit_cnt = 1;
836
846
  int j;
837
-
847
+
838
848
  for (i = 1; i < the_rserver.worker_cnt; i++) {
839
849
  kill(the_rserver.worker_pids[i], SIGKILL);
840
850
  }
@@ -912,7 +922,7 @@ handle(VALUE self, VALUE method, VALUE pattern, VALUE handler) {
912
922
  if (Qtrue == rb_funcall(handler, static_id, 0, Qnil)) {
913
923
  VALUE res = rb_funcall(handler, call_id, 1, Qnil);
914
924
  VALUE bv;
915
-
925
+
916
926
  rb_check_type(res, T_ARRAY);
917
927
  if (3 != RARRAY_LEN(res)) {
918
928
  rb_raise(rb_eArgError, "a rack call() response must be an array of 3 members.");
@@ -932,6 +942,9 @@ handle(VALUE self, VALUE method, VALUE pattern, VALUE handler) {
932
942
  v = rb_ary_entry(bv, i);
933
943
  t = agoo_text_append(t, StringValuePtr(v), (int)RSTRING_LEN(v));
934
944
  }
945
+ if (NULL == t) {
946
+ rb_raise(rb_eNoMemError, "Failed to allocate memory for a response.");
947
+ }
935
948
  if (NULL == agoo_page_immutable(&err, pat, t->text, t->len)) {
936
949
  rb_raise(rb_eArgError, "%s", err.msg);
937
950
  }
@@ -973,7 +986,7 @@ handle_not_found(VALUE self, VALUE handler) {
973
986
  rb_raise(rb_eStandardError, "out of memory.");
974
987
  }
975
988
  rb_gc_register_address((VALUE*)&agoo_server.hook404->handler);
976
-
989
+
977
990
  return Qnil;
978
991
  }
979
992
 
@@ -987,7 +1000,7 @@ handle_not_found(VALUE self, VALUE handler) {
987
1000
  static VALUE
988
1001
  add_mime(VALUE self, VALUE suffix, VALUE type) {
989
1002
  struct _agooErr err = AGOO_ERR_INIT;
990
-
1003
+
991
1004
  if (AGOO_ERR_OK != mime_set(&err, StringValuePtr(suffix), StringValuePtr(type))) {
992
1005
  rb_raise(rb_eArgError, "%s", err.msg);
993
1006
  }
@@ -1014,7 +1027,7 @@ path_group(VALUE self, VALUE path, VALUE dirs) {
1014
1027
  int i;
1015
1028
  int dcnt = (int)RARRAY_LEN(dirs);
1016
1029
  VALUE entry;
1017
-
1030
+
1018
1031
  for (i = dcnt - 1; 0 <= i; i--) {
1019
1032
  entry = rb_ary_entry(dirs, i);
1020
1033
  if (T_STRING != rb_type(entry)) {
@@ -1047,7 +1060,7 @@ path_group(VALUE self, VALUE path, VALUE dirs) {
1047
1060
  static VALUE
1048
1061
  header_rule(VALUE self, VALUE path, VALUE mime, VALUE key, VALUE value) {
1049
1062
  struct _agooErr err = AGOO_ERR_INIT;
1050
-
1063
+
1051
1064
  rb_check_type(path, T_STRING);
1052
1065
  rb_check_type(mime, T_STRING);
1053
1066
  rb_check_type(key, T_STRING);
@@ -1086,7 +1099,7 @@ server_init(VALUE mod) {
1086
1099
  on_message_id = rb_intern("on_message");
1087
1100
  on_request_id = rb_intern("on_request");
1088
1101
  to_i_id = rb_intern("to_i");
1089
-
1102
+
1090
1103
  connect_sym = ID2SYM(rb_intern("CONNECT")); rb_gc_register_address(&connect_sym);
1091
1104
  delete_sym = ID2SYM(rb_intern("DELETE")); rb_gc_register_address(&delete_sym);
1092
1105
  get_sym = ID2SYM(rb_intern("GET")); rb_gc_register_address(&get_sym);
data/ext/agoo/sdl.c CHANGED
@@ -9,14 +9,16 @@
9
9
  #include "graphql.h"
10
10
  #include "sdl.h"
11
11
 
12
- static const char query_str[] = "query";
13
- static const char union_str[] = "union";
14
12
  static const char enum_str[] = "enum";
13
+ static const char extend_str[] = "extend";
14
+ static const char input_str[] = "input";
15
+ static const char interface_str[] = "interface";
15
16
  static const char mutation_str[] = "mutation";
17
+ static const char query_str[] = "query";
18
+ static const char schema_str[] = "schema";
16
19
  static const char subscription_str[] = "subscription";
17
- static const char interface_str[] = "interface";
18
- static const char input_str[] = "input";
19
20
  static const char type_str[] = "type";
21
+ static const char union_str[] = "union";
20
22
 
21
23
  static int make_sel(agooErr err, agooDoc doc, gqlDoc gdoc, gqlOp op, gqlSel *parentp);
22
24
 
@@ -80,56 +82,6 @@ extract_name(agooErr err, agooDoc doc, const char *key, int klen, char *name, si
80
82
  return AGOO_ERR_OK;
81
83
  }
82
84
 
83
- static int
84
- make_scalar(agooErr err, agooDoc doc, const char *desc, int len) {
85
- char name[256];
86
-
87
- if (AGOO_ERR_OK != extract_name(err, doc, "scalar", 6, name, sizeof(name))) {
88
- return err->code;
89
- }
90
- gql_scalar_create(err, name, desc, len);
91
-
92
- return AGOO_ERR_OK;
93
- }
94
-
95
- static int
96
- read_type(agooErr err, agooDoc doc, gqlType *typep, bool *required) {
97
- agoo_doc_skip_white(doc);
98
- if ('[' == *doc->cur) {
99
- gqlType base;
100
- bool not_empty = false;
101
-
102
- doc->cur++;
103
- if (AGOO_ERR_OK != read_type(err, doc, &base, &not_empty)) {
104
- return err->code;
105
- }
106
- agoo_doc_skip_white(doc);
107
- if (']' != *doc->cur) {
108
- return agoo_doc_err(doc, err, "List type not terminated with a ]");
109
- }
110
- doc->cur++;
111
- if (NULL == (*typep = gql_assure_list(err, base, not_empty))) {
112
- return err->code;
113
- }
114
- } else {
115
- char name[256];
116
-
117
- if (0 == read_name(err, doc, name, sizeof(name))) {
118
- return err->code;
119
- }
120
- if (NULL == (*typep = gql_assure_type(err, name))) {
121
- return err->code;
122
- }
123
- }
124
- *required = false;
125
- agoo_doc_skip_white(doc);
126
- if ('!' == *doc->cur) {
127
- *required = true;
128
- doc->cur++;
129
- }
130
- return AGOO_ERR_OK;
131
- }
132
-
133
85
  static int
134
86
  make_use_arg(agooErr err, agooDoc doc, gqlDirUse use) {
135
87
  char name[256];
@@ -195,7 +147,66 @@ extract_dir_use(agooErr err, agooDoc doc, gqlDirUse *uses) {
195
147
  }
196
148
 
197
149
  static int
198
- make_enum(agooErr err, agooDoc doc, const char *desc, size_t dlen) {
150
+ make_scalar(agooErr err, agooDoc doc, const char *desc, int len, bool x) {
151
+ char name[256];
152
+ gqlType type;
153
+
154
+ if (AGOO_ERR_OK != extract_name(err, doc, "scalar", 6, name, sizeof(name))) {
155
+ return err->code;
156
+ }
157
+ if (x) {
158
+ if (NULL == (type = gql_type_get(name))) {
159
+ return agoo_doc_err(doc, err, "%s not defined. Can not be extended.", name);
160
+ }
161
+ } else if (NULL == (type = gql_scalar_create(err, name, desc, len))) {
162
+ return err->code;
163
+ }
164
+ if (AGOO_ERR_OK != extract_dir_use(err, doc, &type->dir)) {
165
+ return err->code;
166
+ }
167
+ return AGOO_ERR_OK;
168
+ }
169
+
170
+ static int
171
+ read_type(agooErr err, agooDoc doc, gqlType *typep, bool *required) {
172
+ agoo_doc_skip_white(doc);
173
+ if ('[' == *doc->cur) {
174
+ gqlType base;
175
+ bool not_empty = false;
176
+
177
+ doc->cur++;
178
+ if (AGOO_ERR_OK != read_type(err, doc, &base, &not_empty)) {
179
+ return err->code;
180
+ }
181
+ agoo_doc_skip_white(doc);
182
+ if (']' != *doc->cur) {
183
+ return agoo_doc_err(doc, err, "List type not terminated with a ]");
184
+ }
185
+ doc->cur++;
186
+ if (NULL == (*typep = gql_assure_list(err, base, not_empty))) {
187
+ return err->code;
188
+ }
189
+ } else {
190
+ char name[256];
191
+
192
+ if (0 == read_name(err, doc, name, sizeof(name))) {
193
+ return err->code;
194
+ }
195
+ if (NULL == (*typep = gql_assure_type(err, name))) {
196
+ return err->code;
197
+ }
198
+ }
199
+ *required = false;
200
+ agoo_doc_skip_white(doc);
201
+ if ('!' == *doc->cur) {
202
+ *required = true;
203
+ doc->cur++;
204
+ }
205
+ return AGOO_ERR_OK;
206
+ }
207
+
208
+ static int
209
+ make_enum(agooErr err, agooDoc doc, const char *desc, size_t dlen, bool x) {
199
210
  char name[256];
200
211
  const char *start;
201
212
  gqlType type;
@@ -214,8 +225,11 @@ make_enum(agooErr err, agooDoc doc, const char *desc, size_t dlen) {
214
225
  return agoo_doc_err(doc, err, "Expected '{'");
215
226
  }
216
227
  doc->cur++;
217
-
218
- if (NULL == (type = gql_enum_create(err, name, desc, dlen))) {
228
+ if (x) {
229
+ if (NULL == (type = gql_type_get(name))) {
230
+ return agoo_doc_err(doc, err, "%s not defined. Can not be extended.", name);
231
+ }
232
+ } else if (NULL == (type = gql_enum_create(err, name, desc, dlen))) {
219
233
  return err->code;
220
234
  }
221
235
  type->dir = uses;
@@ -224,60 +238,69 @@ make_enum(agooErr err, agooDoc doc, const char *desc, size_t dlen) {
224
238
  uses = NULL;
225
239
 
226
240
  if (AGOO_ERR_OK != extract_desc(err, doc, &desc, &dlen)) {
227
- return err->code;
241
+ goto ERROR;
228
242
  }
229
243
  start = doc->cur;
230
244
  agoo_doc_read_token(doc);
231
245
  len = doc->cur - start;
232
246
  if (AGOO_ERR_OK != extract_dir_use(err, doc, &uses)) {
233
- return err->code;
247
+ goto ERROR;
234
248
  }
235
249
  if (doc->cur == start) {
236
250
  if ('}' == *doc->cur) {
237
251
  doc->cur++;
238
252
  break;
239
253
  }
240
- return agoo_doc_err(doc, err, "Invalid Enum value");
254
+ agoo_doc_err(doc, err, "Invalid Enum value");
255
+ goto ERROR;
241
256
  }
242
257
  if (NULL == (ev = gql_enum_append(err, type, start, len, desc, dlen))) {
243
- return err->code;
258
+ goto ERROR;
244
259
  }
245
260
  ev->dir = uses;
246
261
  }
247
262
  return AGOO_ERR_OK;
263
+ ERROR:
264
+ if (!x) {
265
+ gql_type_destroy(type);
266
+ }
267
+ return err->code;
248
268
  }
249
269
 
250
270
  static int
251
- make_union(agooErr err, agooDoc doc, const char *desc, int len) {
271
+ make_union(agooErr err, agooDoc doc, const char *desc, int len, bool x) {
252
272
  char name[256];
253
273
  gqlType type;
254
- gqlDirUse uses = NULL;
255
274
  gqlType member;
256
275
  bool required;
257
276
 
258
277
  if (AGOO_ERR_OK != extract_name(err, doc, union_str, sizeof(union_str) - 1, name, sizeof(name))) {
259
278
  return err->code;
260
279
  }
261
- if (AGOO_ERR_OK != extract_dir_use(err, doc, &uses)) {
280
+ if (x) {
281
+ if (NULL == (type = gql_type_get(name))) {
282
+ return agoo_doc_err(doc, err, "%s not defined. Can not be extended.", name);
283
+ }
284
+ } else if (NULL == (type = gql_union_create(err, name, desc, len))) {
262
285
  return err->code;
263
286
  }
287
+ if (AGOO_ERR_OK != extract_dir_use(err, doc, &type->dir)) {
288
+ goto ERROR;
289
+ }
264
290
  agoo_doc_skip_white(doc);
265
291
  if ('=' != *doc->cur) {
266
- return agoo_doc_err(doc, err, "Expected '='");
292
+ agoo_doc_err(doc, err, "Expected '='");
293
+ goto ERROR;
267
294
  }
268
295
  doc->cur++;
269
296
  agoo_doc_skip_white(doc);
270
297
 
271
- if (NULL == (type = gql_union_create(err, name, desc, len))) {
272
- return err->code;
273
- }
274
- type->dir = uses;
275
298
  while (doc->cur < doc->end) {
276
299
  if (AGOO_ERR_OK != read_type(err, doc, &member, &required)) {
277
- return err->code;
300
+ goto ERROR;
278
301
  }
279
302
  if (AGOO_ERR_OK != gql_union_add(err, type, member)) {
280
- return err->code;
303
+ goto ERROR;
281
304
  }
282
305
  agoo_doc_skip_white(doc);
283
306
  if ('|' != *doc->cur) {
@@ -286,6 +309,11 @@ make_union(agooErr err, agooDoc doc, const char *desc, int len) {
286
309
  doc->cur++; // skip |
287
310
  }
288
311
  return AGOO_ERR_OK;
312
+ ERROR:
313
+ if (!x) {
314
+ gql_type_destroy(type);
315
+ }
316
+ return err->code;
289
317
  }
290
318
 
291
319
  static int
@@ -570,8 +598,6 @@ make_input_arg(agooErr err, agooDoc doc, gqlType type) {
570
598
  if (AGOO_ERR_OK != extract_dir_use(err, doc, &uses)) {
571
599
  return err->code;
572
600
  }
573
- // TBD zzzzzzzz
574
-
575
601
  if (NULL == (arg = gql_input_arg(err, type, name, return_type, desc, dlen, dval, required))) {
576
602
  return err->code;
577
603
  }
@@ -581,77 +607,90 @@ make_input_arg(agooErr err, agooDoc doc, gqlType type) {
581
607
  }
582
608
 
583
609
  static int
584
- make_interface(agooErr err, agooDoc doc, const char *desc, int len) {
610
+ make_interface(agooErr err, agooDoc doc, const char *desc, int len, bool x) {
585
611
  char name[256];
586
612
  gqlType type;
587
- gqlDirUse uses = NULL;
588
613
 
589
614
  if (AGOO_ERR_OK != extract_name(err, doc, interface_str, sizeof(interface_str) - 1, name, sizeof(name))) {
590
615
  return err->code;
591
616
  }
592
- if (AGOO_ERR_OK != extract_dir_use(err, doc, &uses)) {
617
+ if (x) {
618
+ if (NULL == (type = gql_type_get(name))) {
619
+ return agoo_doc_err(doc, err, "%s not defined. Can not be extended.", name);
620
+ }
621
+ } else if (NULL == (type = gql_interface_create(err, name, desc, len))) {
593
622
  return err->code;
594
623
  }
624
+ if (AGOO_ERR_OK != extract_dir_use(err, doc, &type->dir)) {
625
+ goto ERROR;
626
+ }
595
627
  agoo_doc_skip_white(doc);
596
628
  if ('{' != *doc->cur) {
597
- return agoo_doc_err(doc, err, "Expected '{'");
629
+ goto ERROR;
598
630
  }
599
631
  doc->cur++;
600
632
  agoo_doc_skip_white(doc);
601
633
 
602
- if (NULL == (type = gql_interface_create(err, name, desc, len))) {
603
- return err->code;
604
- }
605
- type->dir = uses;
606
634
  while (doc->cur < doc->end) {
607
635
  if ('}' == *doc->cur) {
608
636
  doc->cur++; // skip }
609
637
  break;
610
638
  }
611
639
  if (AGOO_ERR_OK != make_field(err, doc, type)) {
612
- return err->code;
640
+ goto ERROR;
613
641
  }
614
642
  agoo_doc_skip_white(doc);
615
643
  }
616
644
  return AGOO_ERR_OK;
645
+ ERROR:
646
+ if (!x) {
647
+ gql_type_destroy(type);
648
+ }
649
+ return err->code;
617
650
  }
618
651
 
619
652
  static int
620
- make_input(agooErr err, agooDoc doc, const char *desc, int len) {
653
+ make_input(agooErr err, agooDoc doc, const char *desc, int len, bool x) {
621
654
  char name[256];
622
655
  gqlType type;
623
- gqlDirUse uses = NULL;
624
656
 
625
657
  if (AGOO_ERR_OK != extract_name(err, doc, input_str, sizeof(input_str) - 1, name, sizeof(name))) {
626
658
  return err->code;
627
659
  }
628
- if (AGOO_ERR_OK != extract_dir_use(err, doc, &uses)) {
660
+ if (x) {
661
+ if (NULL == (type = gql_type_get(name))) {
662
+ return agoo_doc_err(doc, err, "%s not defined. Can not be extended.", name);
663
+ }
664
+ } else if (NULL == (type = gql_input_create(err, name, desc, len))) {
629
665
  return err->code;
630
666
  }
667
+ if (AGOO_ERR_OK != extract_dir_use(err, doc, &type->dir)) {
668
+ goto ERROR;
669
+ }
631
670
  agoo_doc_skip_white(doc);
632
671
  if ('{' != *doc->cur) {
633
- return agoo_doc_err(doc, err, "Expected '{'");
672
+ agoo_doc_err(doc, err, "Expected '{'");
673
+ goto ERROR;
634
674
  }
635
675
  doc->cur++;
636
676
  agoo_doc_skip_white(doc);
637
677
 
638
- if (NULL == (type = gql_input_create(err, name, desc, len))) {
639
- return err->code;
640
- }
641
- type->dir = uses;
642
-
643
678
  while (doc->cur < doc->end) {
644
679
  if ('}' == *doc->cur) {
645
680
  doc->cur++; // skip }
646
681
  break;
647
682
  }
648
- // TBD zzzzzzzzzz make_arg
649
683
  if (AGOO_ERR_OK != make_input_arg(err, doc, type)) {
650
- return err->code;
684
+ goto ERROR;
651
685
  }
652
686
  agoo_doc_skip_white(doc);
653
687
  }
654
688
  return AGOO_ERR_OK;
689
+ ERROR:
690
+ if (!x) {
691
+ gql_type_destroy(type);
692
+ }
693
+ return err->code;
655
694
  }
656
695
 
657
696
  static int
@@ -705,33 +744,82 @@ extract_interfaces(agooErr err, agooDoc doc, gqlTypeLink *interfacesp) {
705
744
  }
706
745
 
707
746
  static int
708
- make_type(agooErr err, agooDoc doc, const char *desc, int len) {
747
+ make_type(agooErr err, agooDoc doc, const char *desc, int len, bool x) {
709
748
  char name[256];
710
749
  gqlType type;
711
- gqlDirUse uses = NULL;
712
- gqlTypeLink interfaces = NULL;
713
750
 
714
751
  if (AGOO_ERR_OK != extract_name(err, doc, type_str, sizeof(type_str) - 1, name, sizeof(name))) {
715
752
  return err->code;
716
753
  }
717
- if (AGOO_ERR_OK != extract_interfaces(err, doc, &interfaces)) {
754
+ if (x) {
755
+ if (NULL == (type = gql_type_get(name))) {
756
+ return agoo_doc_err(doc, err, "%s not defined. Can not be extended.", name);
757
+ }
758
+ } else if (NULL == (type = gql_type_create(err, name, desc, len, NULL))) {
718
759
  return err->code;
719
760
  }
720
- if (AGOO_ERR_OK != extract_dir_use(err, doc, &uses)) {
721
- return err->code;
761
+ if (AGOO_ERR_OK != extract_interfaces(err, doc, &type->interfaces)) {
762
+ goto ERROR;
763
+ }
764
+ if (AGOO_ERR_OK != extract_dir_use(err, doc, &type->dir)) {
765
+ goto ERROR;
722
766
  }
723
767
  agoo_doc_skip_white(doc);
724
768
  if ('{' != *doc->cur) {
725
- return agoo_doc_err(doc, err, "Expected '{'");
769
+ agoo_doc_err(doc, err, "Expected '{'");
770
+ goto ERROR;
726
771
  }
727
772
  doc->cur++;
728
773
  agoo_doc_skip_white(doc);
729
774
 
730
- if (NULL == (type = gql_type_create(err, name, desc, len, interfaces))) {
731
- return err->code;
775
+ while (doc->cur < doc->end) {
776
+ if ('}' == *doc->cur) {
777
+ doc->cur++; // skip }
778
+ break;
779
+ }
780
+ if (AGOO_ERR_OK != make_field(err, doc, type)) {
781
+ goto ERROR;
782
+ }
783
+ agoo_doc_skip_white(doc);
732
784
  }
733
- type->dir = uses;
785
+ return AGOO_ERR_OK;
786
+ ERROR:
787
+ if (!x) {
788
+ gql_type_destroy(type);
789
+ }
790
+ return err->code;
791
+ }
792
+
793
+ static int
794
+ make_schema(agooErr err, agooDoc doc, const char *desc, int len, bool x) {
795
+ gqlType type;
734
796
 
797
+ if (0 != strncmp(doc->cur, schema_str, sizeof(schema_str) - 1)) {
798
+ return agoo_doc_err(doc, err, "Expected schema key word");
799
+ }
800
+ doc->cur += sizeof(schema_str) - 1;
801
+ if (0 == agoo_doc_skip_white(doc)) {
802
+ return agoo_doc_err(doc, err, "Expected schema key word");
803
+ }
804
+ if (x) {
805
+ if (NULL == (type = gql_type_get(schema_str))) {
806
+ return agoo_doc_err(doc, err, "schema not defined. Can not be extended.");
807
+ }
808
+ } else if (NULL == (type = gql_schema_create(err, desc, len))) {
809
+ return err->code;
810
+ }
811
+ if (AGOO_ERR_OK != extract_dir_use(err, doc, &type->dir)) {
812
+ return err->code;
813
+ }
814
+ agoo_doc_skip_white(doc);
815
+ if ('{' != *doc->cur) {
816
+ if (!x) {
817
+ gql_type_destroy(type);
818
+ }
819
+ return agoo_doc_err(doc, err, "Expected '{'");
820
+ }
821
+ doc->cur++;
822
+ agoo_doc_skip_white(doc);
735
823
  while (doc->cur < doc->end) {
736
824
  if ('}' == *doc->cur) {
737
825
  doc->cur++; // skip }
@@ -745,11 +833,24 @@ make_type(agooErr err, agooDoc doc, const char *desc, int len) {
745
833
  return AGOO_ERR_OK;
746
834
  }
747
835
 
836
+ static int
837
+ extend(agooErr err, agooDoc doc) {
838
+ if (0 != strncmp(doc->cur, extend_str, sizeof(extend_str) - 1)) {
839
+ return agoo_doc_err(doc, err, "Expected extend key word");
840
+ }
841
+ doc->cur += sizeof(extend_str) - 1;
842
+ if (0 == agoo_doc_skip_white(doc)) {
843
+ return agoo_doc_err(doc, err, "Expected extend key word");
844
+ }
845
+ return AGOO_ERR_OK;
846
+ }
847
+
748
848
  int
749
849
  sdl_parse(agooErr err, const char *str, int len) {
750
850
  struct _agooDoc doc;
751
851
  const char *desc = NULL;
752
852
  size_t dlen = 0;
853
+ bool extend_next = false;
753
854
 
754
855
  agoo_doc_init(&doc, str, len);
755
856
 
@@ -761,32 +862,47 @@ sdl_parse(agooErr err, const char *str, int len) {
761
862
  return err->code;
762
863
  }
763
864
  break;
764
- case 's': // scalar
765
- if (AGOO_ERR_OK != make_scalar(err, &doc, desc, dlen)) {
766
- return err->code;
865
+ case 's': // schema or scalar
866
+ if (6 < (doc.end - doc.cur) && 'c' == doc.cur[1]) {
867
+ if ('a' == doc.cur[2]) {
868
+ if (AGOO_ERR_OK != make_scalar(err, &doc, desc, dlen, extend_next)) {
869
+ return err->code;
870
+ }
871
+ desc = NULL;
872
+ dlen = 0;
873
+ break;
874
+ } else {
875
+ if (AGOO_ERR_OK != make_schema(err, &doc, desc, dlen, extend_next)) {
876
+ return err->code;
877
+ }
878
+ desc = NULL;
879
+ dlen = 0;
880
+ break;
881
+ }
767
882
  }
768
- desc = NULL;
769
- dlen = 0;
770
- break;
771
- case 'e': // enum, and extend interface or type
883
+ return agoo_doc_err(&doc, err, "Unknown directive");
884
+ case 'e': // enum or extend
772
885
  if (4 < (doc.end - doc.cur)) {
773
886
  if ('n' == doc.cur[1]) {
774
- if (AGOO_ERR_OK != make_enum(err, &doc, desc, dlen)) {
887
+ if (AGOO_ERR_OK != make_enum(err, &doc, desc, dlen, extend_next)) {
775
888
  return err->code;
776
889
  }
777
890
  desc = NULL;
778
891
  dlen = 0;
779
892
  break;
780
893
  } else {
781
- // TBD extend
894
+ if (AGOO_ERR_OK != extend(err, &doc)) {
895
+ return err->code;
896
+ }
782
897
  desc = NULL;
783
898
  dlen = 0;
899
+ extend_next = true;
784
900
  break;
785
901
  }
786
902
  }
787
903
  return agoo_doc_err(&doc, err, "Unknown directive");
788
904
  case 'u': // union
789
- if (AGOO_ERR_OK != make_union(err, &doc, desc, dlen)) {
905
+ if (AGOO_ERR_OK != make_union(err, &doc, desc, dlen, extend_next)) {
790
906
  return err->code;
791
907
  }
792
908
  desc = NULL;
@@ -800,7 +916,7 @@ sdl_parse(agooErr err, const char *str, int len) {
800
916
  dlen = 0;
801
917
  break;
802
918
  case 't': // type
803
- if (AGOO_ERR_OK != make_type(err, &doc, desc, dlen)) {
919
+ if (AGOO_ERR_OK != make_type(err, &doc, desc, dlen, extend_next)) {
804
920
  return err->code;
805
921
  }
806
922
  desc = NULL;
@@ -809,14 +925,14 @@ sdl_parse(agooErr err, const char *str, int len) {
809
925
  case 'i': // interface, input
810
926
  if (5 < (doc.end - doc.cur) && 'n' == doc.cur[1]) {
811
927
  if ('p' == doc.cur[2]) {
812
- if (AGOO_ERR_OK != make_input(err, &doc, desc, dlen)) {
928
+ if (AGOO_ERR_OK != make_input(err, &doc, desc, dlen, extend_next)) {
813
929
  return err->code;
814
930
  }
815
931
  desc = NULL;
816
932
  dlen = 0;
817
933
  break;
818
934
  } else {
819
- if (AGOO_ERR_OK != make_interface(err, &doc, desc, dlen)) {
935
+ if (AGOO_ERR_OK != make_interface(err, &doc, desc, dlen, extend_next)) {
820
936
  return err->code;
821
937
  }
822
938
  desc = NULL;
@@ -1352,6 +1468,7 @@ lookup_field_type(gqlType type, const char *field, bool qroot) {
1352
1468
  gqlType ftype = NULL;
1353
1469
 
1354
1470
  switch (type->kind) {
1471
+ case GQL_SCHEMA:
1355
1472
  case GQL_OBJECT:
1356
1473
  case GQL_INPUT:
1357
1474
  case GQL_INTERFACE: {
@@ -1425,7 +1542,7 @@ validate_doc(agooErr err, gqlDoc doc) {
1425
1542
  gqlFrag frag;
1426
1543
  int cnt;
1427
1544
 
1428
- if (NULL == (schema = gql_type_get("schema"))) {
1545
+ if (NULL == (schema = gql_root_type())) {
1429
1546
  return agoo_err_set(err, AGOO_ERR_EVAL, "No root (schema) type defined.");
1430
1547
  }
1431
1548
  for (frag = doc->frags; NULL != frag; frag = frag->next) {