github.com/jgarto/itcv@v0.0.0-20180826224514-4eea09c1aa0d/examples/sites/latency/latency.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"sort"
     7  	"time"
     8  
     9  	"honnef.co/go/js/dom"
    10  	"myitcv.io/react"
    11  	"myitcv.io/react/jsx"
    12  )
    13  
    14  //go:generate immutableGen
    15  
    16  type location string
    17  
    18  var (
    19  	locations = [...]location{
    20  		"Oregon",
    21  		"California",
    22  		"Ohio",
    23  		"Virginia",
    24  		"Ireland",
    25  		"Frankfurt",
    26  		"London",
    27  		"Mumbai",
    28  		"Singapore",
    29  		"Seoul",
    30  		"Tokyo",
    31  		"Sydney",
    32  	}
    33  )
    34  
    35  type _Imm_latencies map[location]latency
    36  
    37  type latency struct {
    38  	dns      time.Duration
    39  	tcp      time.Duration
    40  	tls      time.Duration
    41  	wait     time.Duration
    42  	download time.Duration
    43  	total    time.Duration
    44  }
    45  
    46  type LatencyDef struct {
    47  	react.ComponentDef
    48  }
    49  
    50  type LatencyState struct {
    51  	reqId  int
    52  	output bool
    53  
    54  	url    string
    55  	altUrl string
    56  
    57  	*latencies
    58  }
    59  
    60  func Latency() *LatencyElem {
    61  	return buildLatencyElem()
    62  }
    63  
    64  func (l LatencyDef) Render() react.Element {
    65  	var c react.Element
    66  
    67  	if l.State().output {
    68  		c = l.renderOutput()
    69  	} else {
    70  		c = l.renderInput()
    71  	}
    72  
    73  	return react.Div(&react.DivProps{ClassName: "App"},
    74  		react.Div(&react.DivProps{ClassName: "Content center full column"},
    75  			jsx.HTMLElem(`
    76  			<div class="Title margin center">
    77  				<span class="text">Latency</span>
    78  				<span class="subtext">Global latency testing tool</span>
    79  			</div>
    80  			`),
    81  			c,
    82  			jsx.HTMLElem(`
    83  			<div class="Title margin center">
    84  				<br/>
    85  				<span class="subtext" style="font-size:smaller; font-style: italic">(randomly generated results)</span>
    86  				<span class="subtext" style="font-size:smaller; font-style: italic">
    87  					Real, original version <a href="https://latency.apex.sh/" target="_blank">https://latency.apex.sh/</a>
    88  				</span>
    89  			</div>
    90  			`),
    91  		),
    92  	)
    93  }
    94  
    95  func (l LatencyDef) renderInput() react.Element {
    96  	return react.Form(&react.FormProps{ClassName: "LatencyForm"},
    97  		react.Div(&react.DivProps{ClassName: "group"},
    98  			react.Input(&react.InputProps{
    99  				Type:        "text",
   100  				ID:          "url",
   101  				Placeholder: "url to test (can be anything)",
   102  				Value:       l.State().url,
   103  				OnChange:    urlChange{l},
   104  			}),
   105  			react.Input(&react.InputProps{
   106  				Type:        "text",
   107  				ID:          "altUrl",
   108  				Placeholder: "comparison url (not used)",
   109  				Value:       l.State().altUrl,
   110  				OnChange:    altUrlChange{l},
   111  			}),
   112  		),
   113  		react.Button(
   114  			&react.ButtonProps{
   115  				ClassName: "Button small",
   116  				OnClick:   check{l},
   117  			},
   118  			react.S("Start"),
   119  		),
   120  	)
   121  }
   122  
   123  const (
   124  	// gross hack for now
   125  	resultWidth = 500.0
   126  )
   127  
   128  func (l *LatencyDef) renderOutput() react.Element {
   129  	var regions []react.Element
   130  
   131  	ls := l.State().latencies
   132  
   133  	maxTot := time.Duration(0)
   134  
   135  	for _, lat := range ls.Range() {
   136  		if lat.total > maxTot {
   137  			maxTot = lat.total
   138  		}
   139  	}
   140  
   141  	awfulTime := maxTot / 3
   142  	okTime := maxTot * 2 / 3
   143  
   144  	for _, v := range locations {
   145  		regClass := "Region"
   146  
   147  		timings := []react.Element{
   148  			react.Span(&react.SpanProps{ClassName: "total"}, react.S("0ms")),
   149  		}
   150  
   151  		res, ok := ls.Get(v)
   152  		if ok {
   153  			if res.total < awfulTime {
   154  				regClass += " with-timings speed-awful"
   155  			} else if res.total < okTime {
   156  				regClass += " with-timings speed-ok"
   157  			} else {
   158  				regClass += " with-timings speed-fast"
   159  			}
   160  
   161  			genTiming := func(f time.Duration, n, l string) *react.SpanElem {
   162  				w := fmt.Sprintf("%.3fpx", float64(f)/float64(maxTot)*resultWidth)
   163  				rs := fmt.Sprintf("%v (%v)", l, f)
   164  
   165  				return react.Span(
   166  					&react.SpanProps{
   167  						ClassName: "timing " + n,
   168  						Style:     &react.CSS{Width: w},
   169  					},
   170  					react.S(rs),
   171  				)
   172  			}
   173  
   174  			timings = []react.Element{
   175  				genTiming(res.dns, "dns", "DNS"),
   176  				genTiming(res.tcp, "tcp", "TCP"),
   177  				genTiming(res.tls, "tls", "TLS"),
   178  				genTiming(res.wait, "wait", "Wait"),
   179  				genTiming(res.download, "download", "Download"),
   180  				react.Span(&react.SpanProps{ClassName: "total"}, react.S(fmt.Sprintf("%v", res.total))),
   181  			}
   182  		}
   183  
   184  		rd := react.Div(&react.DivProps{ClassName: regClass},
   185  			react.Span(&react.SpanProps{ClassName: "name"}, react.S(v)),
   186  			react.Div(&react.DivProps{ClassName: "Results"},
   187  				react.Div(&react.DivProps{ClassName: "Timings"}, timings...),
   188  			),
   189  		)
   190  
   191  		regions = append(regions, rd)
   192  	}
   193  
   194  	return react.Div(&react.DivProps{ClassName: "Regions"},
   195  		regions...,
   196  	)
   197  }
   198  
   199  func (l *LatencyDef) reset(e *react.SyntheticMouseEvent) {
   200  	s := l.State()
   201  	s.output = false
   202  	s.reqId++
   203  	l.SetState(s)
   204  
   205  	e.PreventDefault()
   206  }
   207  
   208  type urlChange struct{ l LatencyDef }
   209  type altUrlChange struct{ l LatencyDef }
   210  type check struct{ l LatencyDef }
   211  
   212  func (u urlChange) OnChange(se *react.SyntheticEvent) {
   213  	target := se.Target().(*dom.HTMLInputElement)
   214  	s := u.l.State()
   215  	s.url = target.Value
   216  	u.l.SetState(s)
   217  }
   218  
   219  func (a altUrlChange) OnChange(se *react.SyntheticEvent) {
   220  	target := se.Target().(*dom.HTMLInputElement)
   221  	s := a.l.State()
   222  	s.altUrl = target.Value
   223  	a.l.SetState(s)
   224  }
   225  
   226  // this could clearly be replace by something that actually checks
   227  // the realy latencies instead of randomly generating them
   228  func (c check) OnClick(e *react.SyntheticMouseEvent) {
   229  	l := c.l
   230  
   231  	reqId := l.State().reqId
   232  
   233  	for _, v := range locations {
   234  		loc := v
   235  		to := rand.Int63n(3000) * int64(time.Millisecond)
   236  
   237  		go func() {
   238  			<-time.After(time.Duration(to))
   239  			s := l.State()
   240  
   241  			if s.reqId == reqId {
   242  				lat := latency{}
   243  
   244  				ints := make([]int64, 4)
   245  
   246  				for i := range ints {
   247  					ints[i] = rand.Int63n(to)
   248  				}
   249  
   250  				ints = append([]int64{0}, ints...)
   251  				ints = append(ints, to)
   252  
   253  				sort.Slice(ints, func(i, j int) bool {
   254  					return ints[i] < ints[j]
   255  				})
   256  
   257  				vs := make([]time.Duration, len(ints)-1)
   258  
   259  				for i := range vs {
   260  					vs[i] = time.Duration(ints[i+1] - ints[i])
   261  				}
   262  
   263  				lat.dns = vs[0]
   264  				lat.tcp = vs[1]
   265  				lat.tls = vs[2]
   266  				lat.wait = vs[3]
   267  				lat.download = vs[4]
   268  				lat.total = time.Duration(to)
   269  
   270  				s.latencies = s.latencies.Set(loc, lat)
   271  
   272  				l.SetState(s)
   273  			}
   274  
   275  		}()
   276  	}
   277  
   278  	s := l.State()
   279  	s.output = true
   280  	s.latencies = newLatencies()
   281  	l.SetState(s)
   282  
   283  	e.PreventDefault()
   284  }