24
"github.com/cubefs/cubefs/proto"
25
client2 "github.com/cubefs/cubefs/sdk/graphql/client"
26
"github.com/cubefs/cubefs/util/log"
27
"github.com/samsarahq/thunder/batch"
28
"github.com/samsarahq/thunder/graphql"
29
"github.com/samsarahq/thunder/reactive"
32
type graphqlProxyHandler struct {
33
client *client2.MasterGClient
36
func NewProxyHandler(client *client2.MasterGClient) *graphqlProxyHandler {
37
return &graphqlProxyHandler{client: client}
40
func Token(r *http.Request) (string, error) {
41
if token := r.Header.Get(proto.HeadAuthorized); token != "" {
45
if err := r.ParseForm(); err != nil {
49
return r.Form.Get(proto.ParamAuthorized), nil
52
type httpResponse struct {
53
Data interface{} `json:"data,omitempty"`
54
Errors []string `json:"errors,omitempty"`
57
type httpPostBody struct {
58
Query string `json:"query"`
59
Variables map[string]interface{} `json:"variables"`
62
func writeResponse(w http.ResponseWriter, code int, value interface{}, err error) {
63
w.Header().Set("Access-Control-Allow-Origin", "*")
64
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")
65
w.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, X-Requested-With")
66
w.Header().Set("Access-Control-Allow-Credentials", "true")
68
response := httpResponse{}
73
Messge string `json:"message"`
74
Code int `json:"code"`
80
v, e := json.Marshal(msg)
82
v = []byte(fmt.Sprintf("marshal has err , real err is:[%s]", err.Error()))
85
response.Errors = []string{string(v)}
90
responseJSON, err := json.Marshal(response)
92
http.Error(w, err.Error(), http.StatusInternalServerError)
95
if w.Header().Get("Content-Type") == "" {
96
w.Header().Set("Content-Type", "application/json")
99
if _, err := w.Write(responseJSON); err != nil {
100
log.LogWarnf("write reponse has err:[%s]", err.Error())
105
func (h *graphqlProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
106
if r.Method != "POST" {
107
writeResponse(w, http.StatusMethodNotAllowed, nil, errors.New("request must be a POST"))
112
writeResponse(w, http.StatusBadRequest, nil, errors.New("request must include a query"))
118
token, err := Token(r)
120
writeResponse(w, http.StatusUnauthorized, nil, err)
124
ui, err := TokenValidate(token)
126
writeResponse(w, http.StatusProxyAuthRequired, nil, err)
131
header.Set(proto.UserKey, UserID)
133
rep, err := h.client.Proxy(r.Context(), r, header)
136
writeResponse(w, rep.Code, nil, err)
138
writeResponse(w, http.StatusInternalServerError, nil, err)
142
responseJSON, err := json.Marshal(rep)
144
http.Error(w, err.Error(), http.StatusInternalServerError)
147
if w.Header().Get("Content-Type") == "" {
148
w.Header().Set("Content-Type", "application/json")
150
if _, err := w.Write(responseJSON); err != nil {
151
log.LogWarnf("write reponse has err:[%s]", err.Error())
155
type httpHandler struct {
156
schema *graphql.Schema
157
middlewares []graphql.MiddlewareFunc
158
executor graphql.ExecutorRunner
161
func HTTPHandler(schema *graphql.Schema, middlewares ...graphql.MiddlewareFunc) http.Handler {
162
return HTTPHandlerWithExecutor(schema, (graphql.NewExecutor(graphql.NewImmediateGoroutineScheduler())), middlewares...)
165
func HTTPHandlerWithExecutor(schema *graphql.Schema, executor graphql.ExecutorRunner, middlewares ...graphql.MiddlewareFunc) http.Handler {
168
middlewares: middlewares,
173
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
174
if r.Method != "POST" {
175
writeResponse(w, http.StatusMethodNotAllowed, nil, errors.New("request must be a POST"))
180
writeResponse(w, http.StatusBadRequest, nil, errors.New("request must include a query"))
186
if r.RequestURI != "/login" {
187
token, err := Token(r)
189
writeResponse(w, http.StatusUnauthorized, nil, err)
193
ui, err := TokenValidate(token)
195
writeResponse(w, http.StatusProxyAuthRequired, nil, err)
199
ctx = context.WithValue(ctx, proto.UserKey, ui.User_id)
200
ctx = context.WithValue(ctx, proto.UserInfoKey, ui)
203
if r.RequestURI == "/monitor" {
204
value := ctx.Value(proto.UserInfoKey)
206
writeResponse(w, http.StatusProxyAuthRequired, nil, fmt.Errorf("user not found"))
209
ui := value.(*proto.UserInfo)
210
if ui.UserType != proto.UserTypeRoot && ui.UserType != proto.UserTypeAdmin {
211
writeResponse(w, http.StatusProxyAuthRequired, nil, fmt.Errorf("no access visit monitor"))
215
var params httpPostBody
216
if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil {
217
writeResponse(w, http.StatusInternalServerError, nil, err)
221
query, err := graphql.Parse(params.Query, params.Variables)
223
writeResponse(w, http.StatusInternalServerError, nil, err)
227
schema := h.schema.Query
228
if query.Kind == "mutation" {
229
schema = h.schema.Mutation
231
if err := graphql.PrepareQuery(ctx, schema, query.SelectionSet); err != nil {
232
writeResponse(w, http.StatusInternalServerError, nil, err)
236
var wg sync.WaitGroup
240
runner := reactive.NewRerunner(ctx, func(ctx context.Context) (interface{}, error) {
243
ctx = batch.WithBatching(ctx)
245
var middlewares []graphql.MiddlewareFunc
246
middlewares = append(middlewares, h.middlewares...)
247
middlewares = append(middlewares, func(input *graphql.ComputationInput, next graphql.MiddlewareNextFunc) *graphql.ComputationOutput {
248
output := next(input)
249
output.Current, output.Error = e.Execute(input.Ctx, schema, nil, input.ParsedQuery)
253
output := graphql.RunMiddlewares(middlewares, &graphql.ComputationInput{
257
Variables: params.Variables,
259
current, err := output.Current, output.Error
261
if graphql.ErrorCause(err) == context.Canceled {
264
writeResponse(w, http.StatusBadRequest, nil, err)
268
writeResponse(w, http.StatusOK, current, nil)
270
}, graphql.DefaultMinRerunInterval, false)
276
func parseResponseNames(r *http.Request) ([]string, error) {
277
var params httpPostBody
278
if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil {
282
query, err := graphql.Parse(params.Query, params.Variables)
287
list := make([]string, 0)
289
for _, s := range query.Selections {
290
list = append(list, s.Name)
296
func IQLFun(writer http.ResponseWriter, request *http.Request) {
297
writer.Write([]byte(`<!DOCTYPE html>
302
<meta charset=utf-8 />
303
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
304
<title>GraphQL Playground</title>
305
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css" />
306
<link rel="shortcut icon" href="//cdn.jsdelivr.net/npm/graphql-playground-react/build/favicon.png" />
307
<script src="//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js"></script>
312
<style type="text/css">
314
font-family: "Open Sans", sans-serif;
324
-webkit-animation: playgroundIn 0.5s ease-out forwards;
325
animation: playgroundIn 0.5s ease-out forwards;
328
@-webkit-keyframes playgroundIn {
331
-webkit-transform: translateY(10px);
332
-ms-transform: translateY(10px);
333
transform: translateY(10px);
337
-webkit-transform: translateY(0);
338
-ms-transform: translateY(0);
339
transform: translateY(0);
343
@keyframes playgroundIn {
346
-webkit-transform: translateY(10px);
347
-ms-transform: translateY(10px);
348
transform: translateY(10px);
352
-webkit-transform: translateY(0);
353
-ms-transform: translateY(0);
354
transform: translateY(0);
359
<style type="text/css">
361
-webkit-animation: fadeOut 0.5s ease-out forwards;
362
animation: fadeOut 0.5s ease-out forwards;
365
@-webkit-keyframes fadeIn {
368
-webkit-transform: translateY(-10px);
369
-ms-transform: translateY(-10px);
370
transform: translateY(-10px);
374
-webkit-transform: translateY(0);
375
-ms-transform: translateY(0);
376
transform: translateY(0);
383
-webkit-transform: translateY(-10px);
384
-ms-transform: translateY(-10px);
385
transform: translateY(-10px);
389
-webkit-transform: translateY(0);
390
-ms-transform: translateY(0);
391
transform: translateY(0);
395
@-webkit-keyframes fadeOut {
398
-webkit-transform: translateY(0);
399
-ms-transform: translateY(0);
400
transform: translateY(0);
404
-webkit-transform: translateY(-10px);
405
-ms-transform: translateY(-10px);
406
transform: translateY(-10px);
413
-webkit-transform: translateY(0);
414
-ms-transform: translateY(0);
415
transform: translateY(0);
419
-webkit-transform: translateY(-10px);
420
-ms-transform: translateY(-10px);
421
transform: translateY(-10px);
425
@-webkit-keyframes appearIn {
428
-webkit-transform: translateY(0px);
429
-ms-transform: translateY(0px);
430
transform: translateY(0px);
434
-webkit-transform: translateY(0);
435
-ms-transform: translateY(0);
436
transform: translateY(0);
440
@keyframes appearIn {
443
-webkit-transform: translateY(0px);
444
-ms-transform: translateY(0px);
445
transform: translateY(0px);
449
-webkit-transform: translateY(0);
450
-ms-transform: translateY(0);
451
transform: translateY(0);
455
@-webkit-keyframes scaleIn {
457
-webkit-transform: scale(0);
458
-ms-transform: scale(0);
462
-webkit-transform: scale(1);
463
-ms-transform: scale(1);
470
-webkit-transform: scale(0);
471
-ms-transform: scale(0);
475
-webkit-transform: scale(1);
476
-ms-transform: scale(1);
481
@-webkit-keyframes innerDrawIn {
483
stroke-dashoffset: 70;
486
stroke-dashoffset: 140;
489
stroke-dashoffset: 210;
493
@keyframes innerDrawIn {
495
stroke-dashoffset: 70;
498
stroke-dashoffset: 140;
501
stroke-dashoffset: 210;
505
@-webkit-keyframes outerDrawIn {
507
stroke-dashoffset: 76;
510
stroke-dashoffset: 152;
514
@keyframes outerDrawIn {
516
stroke-dashoffset: 76;
519
stroke-dashoffset: 152;
524
-webkit-transform-origin: 0px 0px;
525
-ms-transform-origin: 0px 0px;
526
transform-origin: 0px 0px;
527
-webkit-transform: scale(0);
528
-ms-transform: scale(0);
530
-webkit-animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
531
animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
535
-webkit-transform-origin: 0px 0px;
536
-ms-transform-origin: 0px 0px;
537
transform-origin: 0px 0px;
538
-webkit-transform: scale(0);
539
-ms-transform: scale(0);
541
-webkit-animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
542
animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
546
-webkit-transform-origin: 0px 0px;
547
-ms-transform-origin: 0px 0px;
548
transform-origin: 0px 0px;
549
-webkit-transform: scale(0);
550
-ms-transform: scale(0);
552
-webkit-animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
553
animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
557
-webkit-transform-origin: 0px 0px;
558
-ms-transform-origin: 0px 0px;
559
transform-origin: 0px 0px;
560
-webkit-transform: scale(0);
561
-ms-transform: scale(0);
563
-webkit-animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
564
animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
568
-webkit-transform-origin: 0px 0px;
569
-ms-transform-origin: 0px 0px;
570
transform-origin: 0px 0px;
571
-webkit-transform: scale(0);
572
-ms-transform: scale(0);
574
-webkit-animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
575
animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
579
-webkit-transform-origin: 0px 0px;
580
-ms-transform-origin: 0px 0px;
581
transform-origin: 0px 0px;
582
-webkit-transform: scale(0);
583
-ms-transform: scale(0);
585
-webkit-animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
586
animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
590
-webkit-transform-origin: 64px 28px;
591
-ms-transform-origin: 64px 28px;
592
transform-origin: 64px 28px;
593
-webkit-transform: scale(0);
594
-ms-transform: scale(0);
596
-webkit-animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
597
animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
601
-webkit-transform-origin: 95.98500061035156px 46.510000228881836px;
602
-ms-transform-origin: 95.98500061035156px 46.510000228881836px;
603
transform-origin: 95.98500061035156px 46.510000228881836px;
604
-webkit-transform: scale(0);
605
-ms-transform: scale(0);
607
-webkit-animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
608
animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
612
-webkit-transform-origin: 95.97162628173828px 83.4900016784668px;
613
-ms-transform-origin: 95.97162628173828px 83.4900016784668px;
614
transform-origin: 95.97162628173828px 83.4900016784668px;
615
-webkit-transform: scale(0);
616
-ms-transform: scale(0);
618
-webkit-animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
619
animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
623
-webkit-transform-origin: 64px 101.97999572753906px;
624
-ms-transform-origin: 64px 101.97999572753906px;
625
transform-origin: 64px 101.97999572753906px;
626
-webkit-transform: scale(0);
627
-ms-transform: scale(0);
629
-webkit-animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
630
animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
634
-webkit-transform-origin: 32.03982162475586px 83.4900016784668px;
635
-ms-transform-origin: 32.03982162475586px 83.4900016784668px;
636
transform-origin: 32.03982162475586px 83.4900016784668px;
637
-webkit-transform: scale(0);
638
-ms-transform: scale(0);
640
-webkit-animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
641
animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
645
-webkit-transform-origin: 32.033552169799805px 46.510000228881836px;
646
-ms-transform-origin: 32.033552169799805px 46.510000228881836px;
647
transform-origin: 32.033552169799805px 46.510000228881836px;
648
-webkit-transform: scale(0);
649
-ms-transform: scale(0);
651
-webkit-animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
652
animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
657
stroke-dasharray: 76;
658
-webkit-animation: outerDrawIn 0.5s ease-out forwards 0.3333333333333333s, appearIn 0.1s ease-out forwards 0.3333333333333333s;
659
animation: outerDrawIn 0.5s ease-out forwards 0.3333333333333333s, appearIn 0.1s ease-out forwards 0.3333333333333333s;
660
-webkit-animation-iteration-count: 1, 1;
661
animation-iteration-count: 1, 1;
666
stroke-dasharray: 76;
667
-webkit-animation: outerDrawIn 0.5s ease-out forwards 0.5333333333333333s, appearIn 0.1s ease-out forwards 0.5333333333333333s;
668
animation: outerDrawIn 0.5s ease-out forwards 0.5333333333333333s, appearIn 0.1s ease-out forwards 0.5333333333333333s;
669
-webkit-animation-iteration-count: 1, 1;
670
animation-iteration-count: 1, 1;
675
stroke-dasharray: 76;
676
-webkit-animation: outerDrawIn 0.5s ease-out forwards 0.7333333333333334s, appearIn 0.1s ease-out forwards 0.7333333333333334s;
677
animation: outerDrawIn 0.5s ease-out forwards 0.7333333333333334s, appearIn 0.1s ease-out forwards 0.7333333333333334s;
678
-webkit-animation-iteration-count: 1, 1;
679
animation-iteration-count: 1, 1;
684
stroke-dasharray: 76;
685
-webkit-animation: outerDrawIn 0.5s ease-out forwards 0.9333333333333333s, appearIn 0.1s ease-out forwards 0.9333333333333333s;
686
animation: outerDrawIn 0.5s ease-out forwards 0.9333333333333333s, appearIn 0.1s ease-out forwards 0.9333333333333333s;
687
-webkit-animation-iteration-count: 1, 1;
688
animation-iteration-count: 1, 1;
693
stroke-dasharray: 76;
694
-webkit-animation: outerDrawIn 0.5s ease-out forwards 1.1333333333333333s, appearIn 0.1s ease-out forwards 1.1333333333333333s;
695
animation: outerDrawIn 0.5s ease-out forwards 1.1333333333333333s, appearIn 0.1s ease-out forwards 1.1333333333333333s;
696
-webkit-animation-iteration-count: 1, 1;
697
animation-iteration-count: 1, 1;
702
stroke-dasharray: 76;
703
-webkit-animation: outerDrawIn 0.5s ease-out forwards 1.3333333333333333s, appearIn 0.1s ease-out forwards 1.3333333333333333s;
704
animation: outerDrawIn 0.5s ease-out forwards 1.3333333333333333s, appearIn 0.1s ease-out forwards 1.3333333333333333s;
705
-webkit-animation-iteration-count: 1, 1;
706
animation-iteration-count: 1, 1;
711
stroke-dasharray: 70;
712
-webkit-animation: innerDrawIn 1s ease-in-out forwards 1.3666666666666667s, appearIn 0.1s linear forwards 1.3666666666666667s;
713
animation: innerDrawIn 1s ease-in-out forwards 1.3666666666666667s, appearIn 0.1s linear forwards 1.3666666666666667s;
714
-webkit-animation-iteration-count: infinite, 1;
715
animation-iteration-count: infinite, 1;
720
stroke-dasharray: 70;
721
-webkit-animation: innerDrawIn 1s ease-in-out forwards 1.5333333333333332s, appearIn 0.1s linear forwards 1.5333333333333332s;
722
animation: innerDrawIn 1s ease-in-out forwards 1.5333333333333332s, appearIn 0.1s linear forwards 1.5333333333333332s;
723
-webkit-animation-iteration-count: infinite, 1;
724
animation-iteration-count: infinite, 1;
729
stroke-dasharray: 70;
730
-webkit-animation: innerDrawIn 1s ease-in-out forwards 1.7000000000000002s, appearIn 0.1s linear forwards 1.7000000000000002s;
731
animation: innerDrawIn 1s ease-in-out forwards 1.7000000000000002s, appearIn 0.1s linear forwards 1.7000000000000002s;
732
-webkit-animation-iteration-count: infinite, 1;
733
animation-iteration-count: infinite, 1;
740
display: -webkit-box;
741
display: -webkit-flex;
742
display: -ms-flexbox;
744
-webkit-align-items: center;
745
-webkit-box-align: center;
746
-ms-flex-align: center;
748
-webkit-box-pack: center;
749
-webkit-justify-content: center;
750
-ms-flex-pack: center;
751
justify-content: center;
752
-webkit-flex-direction: column;
753
-ms-flex-direction: column;
754
flex-direction: column;
762
-webkit-animation: fadeIn 0.5s ease-out forwards;
763
animation: fadeIn 0.5s ease-out forwards;
770
color: rgba(255, 255, 255, 0.6);
772
-webkit-animation: fadeIn 0.5s ease-out forwards;
773
animation: fadeIn 0.5s ease-out forwards;
780
<div id="loading-wrapper">
781
<svg class="logo" viewBox="0 0 128 128" xmlns:xlink="http://www.w3.org/1999/xlink">
782
<title>GraphQL Playground Logo</title>
784
<linearGradient id="linearGradient-1" x1="4.86%" x2="96.21%" y1="0%" y2="99.66%">
785
<stop stop-color="#E00082" stop-opacity=".8" offset="0%"></stop>
786
<stop stop-color="#E00082" offset="100%"></stop>
790
<rect id="Gradient" width="127.96" height="127.96" y="1" fill="url(#linearGradient-1)" rx="4"></rect>
791
<path id="Border" fill="#E00082" fill-rule="nonzero" d="M4.7 2.84c-1.58 0-2.86 1.28-2.86 2.85v116.57c0 1.57 1.28 2.84 2.85 2.84h116.57c1.57 0 2.84-1.26 2.84-2.83V5.67c0-1.55-1.26-2.83-2.83-2.83H4.67zM4.7 0h116.58c3.14 0 5.68 2.55 5.68 5.7v116.58c0 3.14-2.54 5.68-5.68 5.68H4.68c-3.13 0-5.68-2.54-5.68-5.68V5.68C-1 2.56 1.55 0 4.7 0z"></path>
792
<path class="bglIGM" x="64" y="28" fill="#fff" d="M64 36c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8" style="transform: translate(100px, 100px);"></path>
793
<path class="ksxRII" x="95.98500061035156" y="46.510000228881836" fill="#fff" d="M89.04 50.52c-2.2-3.84-.9-8.73 2.94-10.96 3.83-2.2 8.72-.9 10.95 2.94 2.2 3.84.9 8.73-2.94 10.96-3.85 2.2-8.76.9-10.97-2.94"
794
style="transform: translate(100px, 100px);"></path>
795
<path class="cWrBmb" x="95.97162628173828" y="83.4900016784668" fill="#fff" d="M102.9 87.5c-2.2 3.84-7.1 5.15-10.94 2.94-3.84-2.2-5.14-7.12-2.94-10.96 2.2-3.84 7.12-5.15 10.95-2.94 3.86 2.23 5.16 7.12 2.94 10.96"
796
style="transform: translate(100px, 100px);"></path>
797
<path class="Wnusb" x="64" y="101.97999572753906" fill="#fff" d="M64 110c-4.43 0-8-3.6-8-8.02 0-4.44 3.57-8.02 8-8.02s8 3.58 8 8.02c0 4.4-3.57 8.02-8 8.02"
798
style="transform: translate(100px, 100px);"></path>
799
<path class="bfPqf" x="32.03982162475586" y="83.4900016784668" fill="#fff" d="M25.1 87.5c-2.2-3.84-.9-8.73 2.93-10.96 3.83-2.2 8.72-.9 10.95 2.94 2.2 3.84.9 8.73-2.94 10.96-3.85 2.2-8.74.9-10.95-2.94"
800
style="transform: translate(100px, 100px);"></path>
801
<path class="edRCTN" x="32.033552169799805" y="46.510000228881836" fill="#fff" d="M38.96 50.52c-2.2 3.84-7.12 5.15-10.95 2.94-3.82-2.2-5.12-7.12-2.92-10.96 2.2-3.84 7.12-5.15 10.95-2.94 3.83 2.23 5.14 7.12 2.94 10.96"
802
style="transform: translate(100px, 100px);"></path>
803
<path class="iEGVWn" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M63.55 27.5l32.9 19-32.9-19z"></path>
804
<path class="bsocdx" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M96 46v38-38z"></path>
805
<path class="jAZXmP" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M96.45 84.5l-32.9 19 32.9-19z"></path>
806
<path class="hSeArx" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M64.45 103.5l-32.9-19 32.9 19z"></path>
807
<path class="bVgqGk" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M32 84V46v38z"></path>
808
<path class="hEFqBt" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M31.55 46.5l32.9-19-32.9 19z"></path>
809
<path class="dzEKCM" id="Triangle-Bottom" stroke="#fff" stroke-width="4" d="M30 84h70" stroke-linecap="round"></path>
810
<path class="DYnPx" id="Triangle-Left" stroke="#fff" stroke-width="4" d="M65 26L30 87" stroke-linecap="round"></path>
811
<path class="hjPEAQ" id="Triangle-Right" stroke="#fff" stroke-width="4" d="M98 87L63 26" stroke-linecap="round"></path>
814
<div class="text">Loading
815
<span class="dGfHfc">GraphQL Playground</span>
820
<script type="text/javascript">
821
window.addEventListener('load', function (event) {
823
const loadingWrapper = document.getElementById('loading-wrapper');
824
loadingWrapper.classList.add('fadeOut');
827
const root = document.getElementById('root');
828
root.classList.add('playgroundIn');
830
GraphQLPlayground.init(root, { endpoint: "/", subscriptionEndpoint: "" })