cubefs

Форк
0
/
handler.go 
835 строк · 26.3 Кб
1
/*
2
 * MIT License
3
 * Copyright (c) 2016 Samsara Networks Inc.
4
 * Modifications copyright 2020 The CubeFS Authors.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 */
13

14
package cutil
15

16
import (
17
	"context"
18
	"encoding/json"
19
	"errors"
20
	"fmt"
21
	"net/http"
22
	"sync"
23

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"
30
)
31

32
type graphqlProxyHandler struct {
33
	client *client2.MasterGClient
34
}
35

36
func NewProxyHandler(client *client2.MasterGClient) *graphqlProxyHandler {
37
	return &graphqlProxyHandler{client: client}
38
}
39

40
func Token(r *http.Request) (string, error) {
41
	if token := r.Header.Get(proto.HeadAuthorized); token != "" {
42
		return token, nil
43
	}
44

45
	if err := r.ParseForm(); err != nil {
46
		return "", err
47
	}
48

49
	return r.Form.Get(proto.ParamAuthorized), nil
50
}
51

52
type httpResponse struct {
53
	Data   interface{} `json:"data,omitempty"`
54
	Errors []string    `json:"errors,omitempty"`
55
}
56

57
type httpPostBody struct {
58
	Query     string                 `json:"query"`
59
	Variables map[string]interface{} `json:"variables"`
60
}
61

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")
67

68
	response := httpResponse{}
69

70
	if err != nil {
71

72
		msg := struct {
73
			Messge string `json:"message"`
74
			Code   int    `json:"code"`
75
		}{
76
			Messge: err.Error(),
77
			Code:   code,
78
		}
79

80
		v, e := json.Marshal(msg)
81
		if e != nil {
82
			v = []byte(fmt.Sprintf("marshal has err , real err is:[%s]", err.Error()))
83
		}
84

85
		response.Errors = []string{string(v)}
86
	} else {
87
		response.Data = value
88
	}
89

90
	responseJSON, err := json.Marshal(response)
91
	if err != nil {
92
		http.Error(w, err.Error(), http.StatusInternalServerError)
93
		return
94
	}
95
	if w.Header().Get("Content-Type") == "" {
96
		w.Header().Set("Content-Type", "application/json")
97
	}
98

99
	if _, err := w.Write(responseJSON); err != nil {
100
		log.LogWarnf("write reponse has err:[%s]", err.Error())
101
	}
102
}
103

104
// This code is borrowed https://github.com/samsarahq/thunder
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"))
108
		return
109
	}
110

111
	if r.Body == nil {
112
		writeResponse(w, http.StatusBadRequest, nil, errors.New("request must include a query"))
113
		return
114
	}
115

116
	header := r.Header
117

118
	token, err := Token(r)
119
	if err != nil {
120
		writeResponse(w, http.StatusUnauthorized, nil, err)
121
		return
122
	}
123

124
	ui, err := TokenValidate(token)
125
	if err != nil {
126
		writeResponse(w, http.StatusProxyAuthRequired, nil, err)
127
		return
128
	}
129

130
	UserID := ui.User_id
131
	header.Set(proto.UserKey, UserID)
132

133
	rep, err := h.client.Proxy(r.Context(), r, header)
134
	if err != nil {
135
		if rep != nil {
136
			writeResponse(w, rep.Code, nil, err)
137
		} else {
138
			writeResponse(w, http.StatusInternalServerError, nil, err)
139
		}
140
		return
141
	}
142
	responseJSON, err := json.Marshal(rep)
143
	if err != nil {
144
		http.Error(w, err.Error(), http.StatusInternalServerError)
145
		return
146
	}
147
	if w.Header().Get("Content-Type") == "" {
148
		w.Header().Set("Content-Type", "application/json")
149
	}
150
	if _, err := w.Write(responseJSON); err != nil {
151
		log.LogWarnf("write reponse has err:[%s]", err.Error())
152
	}
153
}
154

155
type httpHandler struct {
156
	schema      *graphql.Schema
157
	middlewares []graphql.MiddlewareFunc
158
	executor    graphql.ExecutorRunner
159
}
160

161
func HTTPHandler(schema *graphql.Schema, middlewares ...graphql.MiddlewareFunc) http.Handler {
162
	return HTTPHandlerWithExecutor(schema, (graphql.NewExecutor(graphql.NewImmediateGoroutineScheduler())), middlewares...)
163
}
164

165
func HTTPHandlerWithExecutor(schema *graphql.Schema, executor graphql.ExecutorRunner, middlewares ...graphql.MiddlewareFunc) http.Handler {
166
	return &httpHandler{
167
		schema:      schema,
168
		middlewares: middlewares,
169
		executor:    executor,
170
	}
171
}
172

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"))
176
		return
177
	}
178

179
	if r.Body == nil {
180
		writeResponse(w, http.StatusBadRequest, nil, errors.New("request must include a query"))
181
		return
182
	}
183

184
	ctx := r.Context()
185

186
	if r.RequestURI != "/login" {
187
		token, err := Token(r)
188
		if err != nil {
189
			writeResponse(w, http.StatusUnauthorized, nil, err)
190
			return
191
		}
192

193
		ui, err := TokenValidate(token)
194
		if err != nil {
195
			writeResponse(w, http.StatusProxyAuthRequired, nil, err)
196
			return
197
		}
198

199
		ctx = context.WithValue(ctx, proto.UserKey, ui.User_id)
200
		ctx = context.WithValue(ctx, proto.UserInfoKey, ui)
201
	}
202

203
	if r.RequestURI == "/monitor" {
204
		value := ctx.Value(proto.UserInfoKey)
205
		if value == nil {
206
			writeResponse(w, http.StatusProxyAuthRequired, nil, fmt.Errorf("user not found"))
207
		}
208

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"))
212
		}
213
	}
214

215
	var params httpPostBody
216
	if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
217
		writeResponse(w, http.StatusInternalServerError, nil, err)
218
		return
219
	}
220

221
	query, err := graphql.Parse(params.Query, params.Variables)
222
	if err != nil {
223
		writeResponse(w, http.StatusInternalServerError, nil, err)
224
		return
225
	}
226

227
	schema := h.schema.Query
228
	if query.Kind == "mutation" {
229
		schema = h.schema.Mutation
230
	}
231
	if err := graphql.PrepareQuery(ctx, schema, query.SelectionSet); err != nil {
232
		writeResponse(w, http.StatusInternalServerError, nil, err)
233
		return
234
	}
235

236
	var wg sync.WaitGroup
237
	e := h.executor
238

239
	wg.Add(1)
240
	runner := reactive.NewRerunner(ctx, func(ctx context.Context) (interface{}, error) {
241
		defer wg.Done()
242

243
		ctx = batch.WithBatching(ctx)
244

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)
250
			return output
251
		})
252

253
		output := graphql.RunMiddlewares(middlewares, &graphql.ComputationInput{
254
			Ctx:         ctx,
255
			ParsedQuery: query,
256
			Query:       params.Query,
257
			Variables:   params.Variables,
258
		})
259
		current, err := output.Current, output.Error
260
		if err != nil {
261
			if graphql.ErrorCause(err) == context.Canceled {
262
				return nil, err
263
			}
264
			writeResponse(w, http.StatusBadRequest, nil, err)
265
			return nil, err
266
		}
267

268
		writeResponse(w, http.StatusOK, current, nil)
269
		return nil, nil
270
	}, graphql.DefaultMinRerunInterval, false)
271

272
	wg.Wait()
273
	runner.Stop()
274
}
275

276
func parseResponseNames(r *http.Request) ([]string, error) {
277
	var params httpPostBody
278
	if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
279
		return nil, err
280
	}
281

282
	query, err := graphql.Parse(params.Query, params.Variables)
283
	if err != nil {
284
		return nil, err
285
	}
286

287
	list := make([]string, 0)
288

289
	for _, s := range query.Selections {
290
		list = append(list, s.Name)
291
	}
292

293
	return list, nil
294
}
295

296
func IQLFun(writer http.ResponseWriter, request *http.Request) {
297
	writer.Write([]byte(`<!DOCTYPE html>
298

299
<html>
300

301
<head>
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>
308

309
</head>
310

311
<body>
312
  <style type="text/css">
313
    html {
314
      font-family: "Open Sans", sans-serif;
315
      overflow: hidden;
316
    }
317

318
    body {
319
      margin: 0;
320
      background: #172a3a;
321
    }
322

323
    .playgroundIn {
324
      -webkit-animation: playgroundIn 0.5s ease-out forwards;
325
      animation: playgroundIn 0.5s ease-out forwards;
326
    }
327

328
    @-webkit-keyframes playgroundIn {
329
      from {
330
        opacity: 0;
331
        -webkit-transform: translateY(10px);
332
        -ms-transform: translateY(10px);
333
        transform: translateY(10px);
334
      }
335
      to {
336
        opacity: 1;
337
        -webkit-transform: translateY(0);
338
        -ms-transform: translateY(0);
339
        transform: translateY(0);
340
      }
341
    }
342

343
    @keyframes playgroundIn {
344
      from {
345
        opacity: 0;
346
        -webkit-transform: translateY(10px);
347
        -ms-transform: translateY(10px);
348
        transform: translateY(10px);
349
      }
350
      to {
351
        opacity: 1;
352
        -webkit-transform: translateY(0);
353
        -ms-transform: translateY(0);
354
        transform: translateY(0);
355
      }
356
    }
357
  </style>
358

359
  <style type="text/css">
360
    .fadeOut {
361
      -webkit-animation: fadeOut 0.5s ease-out forwards;
362
      animation: fadeOut 0.5s ease-out forwards;
363
    }
364

365
    @-webkit-keyframes fadeIn {
366
      from {
367
        opacity: 0;
368
        -webkit-transform: translateY(-10px);
369
        -ms-transform: translateY(-10px);
370
        transform: translateY(-10px);
371
      }
372
      to {
373
        opacity: 1;
374
        -webkit-transform: translateY(0);
375
        -ms-transform: translateY(0);
376
        transform: translateY(0);
377
      }
378
    }
379

380
    @keyframes fadeIn {
381
      from {
382
        opacity: 0;
383
        -webkit-transform: translateY(-10px);
384
        -ms-transform: translateY(-10px);
385
        transform: translateY(-10px);
386
      }
387
      to {
388
        opacity: 1;
389
        -webkit-transform: translateY(0);
390
        -ms-transform: translateY(0);
391
        transform: translateY(0);
392
      }
393
    }
394

395
    @-webkit-keyframes fadeOut {
396
      from {
397
        opacity: 1;
398
        -webkit-transform: translateY(0);
399
        -ms-transform: translateY(0);
400
        transform: translateY(0);
401
      }
402
      to {
403
        opacity: 0;
404
        -webkit-transform: translateY(-10px);
405
        -ms-transform: translateY(-10px);
406
        transform: translateY(-10px);
407
      }
408
    }
409

410
    @keyframes fadeOut {
411
      from {
412
        opacity: 1;
413
        -webkit-transform: translateY(0);
414
        -ms-transform: translateY(0);
415
        transform: translateY(0);
416
      }
417
      to {
418
        opacity: 0;
419
        -webkit-transform: translateY(-10px);
420
        -ms-transform: translateY(-10px);
421
        transform: translateY(-10px);
422
      }
423
    }
424

425
    @-webkit-keyframes appearIn {
426
      from {
427
        opacity: 0;
428
        -webkit-transform: translateY(0px);
429
        -ms-transform: translateY(0px);
430
        transform: translateY(0px);
431
      }
432
      to {
433
        opacity: 1;
434
        -webkit-transform: translateY(0);
435
        -ms-transform: translateY(0);
436
        transform: translateY(0);
437
      }
438
    }
439

440
    @keyframes appearIn {
441
      from {
442
        opacity: 0;
443
        -webkit-transform: translateY(0px);
444
        -ms-transform: translateY(0px);
445
        transform: translateY(0px);
446
      }
447
      to {
448
        opacity: 1;
449
        -webkit-transform: translateY(0);
450
        -ms-transform: translateY(0);
451
        transform: translateY(0);
452
      }
453
    }
454

455
    @-webkit-keyframes scaleIn {
456
      from {
457
        -webkit-transform: scale(0);
458
        -ms-transform: scale(0);
459
        transform: scale(0);
460
      }
461
      to {
462
        -webkit-transform: scale(1);
463
        -ms-transform: scale(1);
464
        transform: scale(1);
465
      }
466
    }
467

468
    @keyframes scaleIn {
469
      from {
470
        -webkit-transform: scale(0);
471
        -ms-transform: scale(0);
472
        transform: scale(0);
473
      }
474
      to {
475
        -webkit-transform: scale(1);
476
        -ms-transform: scale(1);
477
        transform: scale(1);
478
      }
479
    }
480

481
    @-webkit-keyframes innerDrawIn {
482
      0% {
483
        stroke-dashoffset: 70;
484
      }
485
      50% {
486
        stroke-dashoffset: 140;
487
      }
488
      100% {
489
        stroke-dashoffset: 210;
490
      }
491
    }
492

493
    @keyframes innerDrawIn {
494
      0% {
495
        stroke-dashoffset: 70;
496
      }
497
      50% {
498
        stroke-dashoffset: 140;
499
      }
500
      100% {
501
        stroke-dashoffset: 210;
502
      }
503
    }
504

505
    @-webkit-keyframes outerDrawIn {
506
      0% {
507
        stroke-dashoffset: 76;
508
      }
509
      100% {
510
        stroke-dashoffset: 152;
511
      }
512
    }
513

514
    @keyframes outerDrawIn {
515
      0% {
516
        stroke-dashoffset: 76;
517
      }
518
      100% {
519
        stroke-dashoffset: 152;
520
      }
521
    }
522

523
    .hHWjkv {
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);
529
      transform: scale(0);
530
      -webkit-animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
531
      animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
532
    }
533

534
    .gCDOzd {
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);
540
      transform: scale(0);
541
      -webkit-animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
542
      animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
543
    }
544

545
    .hmCcxi {
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);
551
      transform: scale(0);
552
      -webkit-animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
553
      animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
554
    }
555

556
    .eHamQi {
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);
562
      transform: scale(0);
563
      -webkit-animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
564
      animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
565
    }
566

567
    .byhgGu {
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);
573
      transform: scale(0);
574
      -webkit-animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
575
      animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
576
    }
577

578
    .llAKP {
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);
584
      transform: scale(0);
585
      -webkit-animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
586
      animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
587
    }
588

589
    .bglIGM {
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);
595
      transform: scale(0);
596
      -webkit-animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
597
      animation: scaleIn 0.25s linear forwards 0.2222222222222222s;
598
    }
599

600
    .ksxRII {
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);
606
      transform: scale(0);
607
      -webkit-animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
608
      animation: scaleIn 0.25s linear forwards 0.4222222222222222s;
609
    }
610

611
    .cWrBmb {
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);
617
      transform: scale(0);
618
      -webkit-animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
619
      animation: scaleIn 0.25s linear forwards 0.6222222222222222s;
620
    }
621

622
    .Wnusb {
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);
628
      transform: scale(0);
629
      -webkit-animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
630
      animation: scaleIn 0.25s linear forwards 0.8222222222222223s;
631
    }
632

633
    .bfPqf {
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);
639
      transform: scale(0);
640
      -webkit-animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
641
      animation: scaleIn 0.25s linear forwards 1.0222222222222221s;
642
    }
643

644
    .edRCTN {
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);
650
      transform: scale(0);
651
      -webkit-animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
652
      animation: scaleIn 0.25s linear forwards 1.2222222222222223s;
653
    }
654

655
    .iEGVWn {
656
      opacity: 0;
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;
662
    }
663

664
    .bsocdx {
665
      opacity: 0;
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;
671
    }
672

673
    .jAZXmP {
674
      opacity: 0;
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;
680
    }
681

682
    .hSeArx {
683
      opacity: 0;
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;
689
    }
690

691
    .bVgqGk {
692
      opacity: 0;
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;
698
    }
699

700
    .hEFqBt {
701
      opacity: 0;
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;
707
    }
708

709
    .dzEKCM {
710
      opacity: 0;
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;
716
    }
717

718
    .DYnPx {
719
      opacity: 0;
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;
725
    }
726

727
    .hjPEAQ {
728
      opacity: 0;
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;
734
    }
735

736
    #loading-wrapper {
737
      position: absolute;
738
      width: 100vw;
739
      height: 100vh;
740
      display: -webkit-box;
741
      display: -webkit-flex;
742
      display: -ms-flexbox;
743
      display: flex;
744
      -webkit-align-items: center;
745
      -webkit-box-align: center;
746
      -ms-flex-align: center;
747
      align-items: 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;
755
    }
756

757
    .logo {
758
      width: 75px;
759
      height: 75px;
760
      margin-bottom: 20px;
761
      opacity: 0;
762
      -webkit-animation: fadeIn 0.5s ease-out forwards;
763
      animation: fadeIn 0.5s ease-out forwards;
764
    }
765

766
    .text {
767
      font-size: 32px;
768
      font-weight: 200;
769
      text-align: center;
770
      color: rgba(255, 255, 255, 0.6);
771
      opacity: 0;
772
      -webkit-animation: fadeIn 0.5s ease-out forwards;
773
      animation: fadeIn 0.5s ease-out forwards;
774
    }
775

776
    .dGfHfc {
777
      font-weight: 400;
778
    }
779
  </style>
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>
783
      <defs>
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>
787
        </linearGradient>
788
      </defs>
789
      <g>
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>
812
      </g>
813
    </svg>
814
    <div class="text">Loading
815
      <span class="dGfHfc">GraphQL Playground</span>
816
    </div>
817
  </div>
818

819
  <div id="root" />
820
  <script type="text/javascript">
821
    window.addEventListener('load', function (event) {
822

823
      const loadingWrapper = document.getElementById('loading-wrapper');
824
      loadingWrapper.classList.add('fadeOut');
825

826

827
      const root = document.getElementById('root');
828
      root.classList.add('playgroundIn');
829

830
      GraphQLPlayground.init(root, { endpoint: "/", subscriptionEndpoint: "" })
831
    })
832
  </script>
833
</body>
834
</html>`))
835
}
836

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.