chore: add peerfinder assets
This commit is contained in:
		
							parent
							
								
									6569c58e37
								
							
						
					
					
						commit
						12716ae972
					
				
							
								
								
									
										119
									
								
								app/gql/graphiql/playground.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								app/gql/graphiql/playground.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,119 @@
 | 
				
			|||||||
 | 
					package graphiql
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					  <head>
 | 
				
			||||||
 | 
					  	<meta charset="utf-8">
 | 
				
			||||||
 | 
					  	<title>{{.title}}</title>
 | 
				
			||||||
 | 
						<style>
 | 
				
			||||||
 | 
							body {
 | 
				
			||||||
 | 
								height: 100%;
 | 
				
			||||||
 | 
								margin: 0;
 | 
				
			||||||
 | 
								width: 100%;
 | 
				
			||||||
 | 
								overflow: hidden;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#graphiql {
 | 
				
			||||||
 | 
								height: 100vh;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						</style>
 | 
				
			||||||
 | 
						<script
 | 
				
			||||||
 | 
							src="https://cdn.jsdelivr.net/npm/react@17.0.2/umd/react.production.min.js"
 | 
				
			||||||
 | 
							integrity="{{.reactSRI}}"
 | 
				
			||||||
 | 
							crossorigin="anonymous"
 | 
				
			||||||
 | 
						></script>
 | 
				
			||||||
 | 
						<script
 | 
				
			||||||
 | 
							src="https://cdn.jsdelivr.net/npm/react-dom@17.0.2/umd/react-dom.production.min.js"
 | 
				
			||||||
 | 
							integrity="{{.reactDOMSRI}}"
 | 
				
			||||||
 | 
							crossorigin="anonymous"
 | 
				
			||||||
 | 
						></script>
 | 
				
			||||||
 | 
					    <link
 | 
				
			||||||
 | 
							rel="stylesheet"
 | 
				
			||||||
 | 
							href="https://cdn.jsdelivr.net/npm/graphiql@{{.version}}/graphiql.min.css"
 | 
				
			||||||
 | 
							x-integrity="{{.cssSRI}}"
 | 
				
			||||||
 | 
							crossorigin="anonymous"
 | 
				
			||||||
 | 
						/>
 | 
				
			||||||
 | 
					  </head>
 | 
				
			||||||
 | 
					  <body>
 | 
				
			||||||
 | 
					    <div id="graphiql">Loading...</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<script
 | 
				
			||||||
 | 
							src="https://cdn.jsdelivr.net/npm/graphiql@{{.version}}/graphiql.min.js"
 | 
				
			||||||
 | 
							x-integrity="{{.jsSRI}}"
 | 
				
			||||||
 | 
							crossorigin="anonymous"
 | 
				
			||||||
 | 
						></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <script>
 | 
				
			||||||
 | 
					{{- if .endpointIsAbsolute}}
 | 
				
			||||||
 | 
					      const url = {{.endpoint}};
 | 
				
			||||||
 | 
					      const subscriptionUrl = {{.subscriptionEndpoint}};
 | 
				
			||||||
 | 
					{{- else}}
 | 
				
			||||||
 | 
					      const url = location.protocol + '//' + location.host + {{.endpoint}};
 | 
				
			||||||
 | 
					      const wsProto = location.protocol == 'https:' ? 'wss:' : 'ws:';
 | 
				
			||||||
 | 
					      const subscriptionUrl = wsProto + '//' + location.host + {{.endpoint}};
 | 
				
			||||||
 | 
					{{- end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const fetcher = GraphiQL.createFetcher({ url, subscriptionUrl });
 | 
				
			||||||
 | 
					      ReactDOM.render(
 | 
				
			||||||
 | 
					        React.createElement(GraphiQL, {
 | 
				
			||||||
 | 
					          fetcher: fetcher,
 | 
				
			||||||
 | 
					          isHeadersEditorEnabled: true,
 | 
				
			||||||
 | 
					          shouldPersistHeaders: true
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					        document.getElementById('graphiql'),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    </script>
 | 
				
			||||||
 | 
					  </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
 | 
					`))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Handler responsible for setting up the playground
 | 
				
			||||||
 | 
					func Handler(title string, endpoint string) http.HandlerFunc {
 | 
				
			||||||
 | 
						return func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
							w.Header().Add("Content-Type", "text/html; charset=UTF-8")
 | 
				
			||||||
 | 
							err := page.Execute(w, map[string]interface{}{
 | 
				
			||||||
 | 
								"title":                title,
 | 
				
			||||||
 | 
								"endpoint":             endpoint,
 | 
				
			||||||
 | 
								"endpointIsAbsolute":   endpointHasScheme(endpoint),
 | 
				
			||||||
 | 
								"subscriptionEndpoint": getSubscriptionEndpoint(endpoint),
 | 
				
			||||||
 | 
								"version":              "2.0.10",
 | 
				
			||||||
 | 
								"cssSRI":               "sha256-gQryfbGYeYFxnJYnfPStPYFt0+uv8RP8Dm++eh00G9c=",
 | 
				
			||||||
 | 
								"jsSRI":                "sha256-qQ6pw7LwTLC+GfzN+cJsYXfVWRKH9O5o7+5H96gTJhQ=",
 | 
				
			||||||
 | 
								"reactSRI":             "sha256-Ipu/TQ50iCCVZBUsZyNJfxrDk0E2yhaEIz0vqI+kFG8=",
 | 
				
			||||||
 | 
								"reactDOMSRI":          "sha256-nbMykgB6tsOFJ7OdVmPpdqMFVk4ZsqWocT6issAPUF0=",
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								panic(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// endpointHasScheme checks if the endpoint has a scheme.
 | 
				
			||||||
 | 
					func endpointHasScheme(endpoint string) bool {
 | 
				
			||||||
 | 
						u, err := url.Parse(endpoint)
 | 
				
			||||||
 | 
						return err == nil && u.Scheme != ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// getSubscriptionEndpoint returns the subscription endpoint for the given
 | 
				
			||||||
 | 
					// endpoint if it is parsable as a URL, or an empty string.
 | 
				
			||||||
 | 
					func getSubscriptionEndpoint(endpoint string) string {
 | 
				
			||||||
 | 
						u, err := url.Parse(endpoint)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch u.Scheme {
 | 
				
			||||||
 | 
						case "https":
 | 
				
			||||||
 | 
							u.Scheme = "wss"
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							u.Scheme = "ws"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return u.String()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								app/peerfinder/assets/bootstrap.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/peerfinder/assets/bootstrap.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										58
									
								
								app/peerfinder/assets/peerfinder.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								app/peerfinder/assets/peerfinder.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					/* Space out content a bit */
 | 
				
			||||||
 | 
					body {
 | 
				
			||||||
 | 
					  padding-top: 20px;
 | 
				
			||||||
 | 
					  padding-bottom: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Everything but the jumbotron gets side spacing for mobile first views */
 | 
				
			||||||
 | 
					.header,
 | 
				
			||||||
 | 
					.footer {
 | 
				
			||||||
 | 
					  padding-right: 15px;
 | 
				
			||||||
 | 
					  padding-left: 15px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Custom page header */
 | 
				
			||||||
 | 
					.header {
 | 
				
			||||||
 | 
					  padding-bottom: 20px;
 | 
				
			||||||
 | 
					  border-bottom: 1px solid #e5e5e5;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/* Make the masthead heading the same height as the navigation */
 | 
				
			||||||
 | 
					.header h3 {
 | 
				
			||||||
 | 
					  margin-top: 0;
 | 
				
			||||||
 | 
					  margin-bottom: 0;
 | 
				
			||||||
 | 
					  line-height: 40px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Custom page footer */
 | 
				
			||||||
 | 
					.footer {
 | 
				
			||||||
 | 
					  padding-top: 19px;
 | 
				
			||||||
 | 
					  color: #777;
 | 
				
			||||||
 | 
					  border-top: 1px solid #e5e5e5;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Customize container */
 | 
				
			||||||
 | 
					@media (min-width: 768px) {
 | 
				
			||||||
 | 
					  .container {
 | 
				
			||||||
 | 
					    max-width: 730px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.container-narrow > hr {
 | 
				
			||||||
 | 
					  margin: 30px 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Responsive: Portrait tablets and up */
 | 
				
			||||||
 | 
					@media screen and (min-width: 768px) {
 | 
				
			||||||
 | 
					  /* Remove the padding we set earlier */
 | 
				
			||||||
 | 
					  .header,
 | 
				
			||||||
 | 
					  .footer {
 | 
				
			||||||
 | 
					    padding-right: 0;
 | 
				
			||||||
 | 
					    padding-left: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  /* Space out the masthead */
 | 
				
			||||||
 | 
					  .header {
 | 
				
			||||||
 | 
					    margin-bottom: 30px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.panel-primary a { color: white; font-weight:bold }
 | 
				
			||||||
							
								
								
									
										21
									
								
								app/peerfinder/layouts/form.tpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								app/peerfinder/layouts/form.tpl
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					<div class="form-group"><label class="col-sm-2 control-label" >Peer Name</label><div class='col-sm-10'><input class="form-control" type=text name=peer_name  value="{$o.peer_name|default:''|escape}"/></div></div>
 | 
				
			||||||
 | 
					<div class="form-group"><label class="col-sm-2 control-label" >IRC Nick</label><div class='col-sm-10'><input class="form-control" type=text name=peer_nick  value="{$o.peer_nick|default:''|escape}"/></div></div>
 | 
				
			||||||
 | 
					<div class="form-group"><label class="col-sm-2 control-label" >Note</label><div class='col-sm-10'><input class="form-control" type=text name=peer_note  value="{$o.peer_note|default:''|escape}"/></div></div>
 | 
				
			||||||
 | 
					<div class="form-group"><label class="col-sm-2 control-label" >Country</label><div class='col-sm-2'><input class="form-control" type=text name=peer_country maxlength=3  value="{$o.peer_country|default:''|escape}"/></div></div>
 | 
				
			||||||
 | 
					<div class="form-group"><label class="col-sm-2 control-label" >VPN Types</label><div class='col-sm-10'><select class="form-control" size=12  multiple name="peer_type[]">
 | 
				
			||||||
 | 
					  <option {$types['openvpn']|default:''} value="openvpn">openvpn</option>
 | 
				
			||||||
 | 
					  <option {$types['gre/ipsec']|default:''} value="gre/ipsec">gre/ipsec</option>
 | 
				
			||||||
 | 
					  <option {$types['gre/plain']|default:''} value="gre/plain">gre/plain</option>
 | 
				
			||||||
 | 
					  <option {$types['fastd']|default:''} value="fastd">fastd</option>
 | 
				
			||||||
 | 
					  <option {$types['tinc']|default:''} value="tinc">tinc</option>
 | 
				
			||||||
 | 
					  <option {$types['zerotier']|default:''} value="zerotier">zerotier</option>
 | 
				
			||||||
 | 
					  <option {$types['wireguard']|default:''} value="wireguard">wireguard</option>
 | 
				
			||||||
 | 
					  <option {$types['pptp']|default:''} value="pptp">pptp</option>
 | 
				
			||||||
 | 
					  <option {$types['l2tp']|default:''} value="l2tp">l2tp</option>
 | 
				
			||||||
 | 
					  <option {$types['other']|default:''} value="other">other</option>
 | 
				
			||||||
 | 
					</select></div></div>
 | 
				
			||||||
 | 
					<div class="form-group"><label class="col-sm-2 control-label" >Address Family</label><div class='col-sm-10'>
 | 
				
			||||||
 | 
					  <label><input type="radio" name="peer_family"  value="1"   {$fam[0]|default:''} /> ipv4 </label>
 | 
				
			||||||
 | 
					  <label><input type="radio" name="peer_family"  value="2"   {$fam[1]|default:''} /> ipv6 </label>
 | 
				
			||||||
 | 
					  <label><input type="radio" name="peer_family"  value="3"   {$fam[2]|default:''} /> both </label>
 | 
				
			||||||
 | 
					</div></div>
 | 
				
			||||||
							
								
								
									
										41
									
								
								app/peerfinder/layouts/main.tpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								app/peerfinder/layouts/main.tpl
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					{{define "main"}}
 | 
				
			||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
 | 
						{{template "meta" .}}
 | 
				
			||||||
 | 
					    <title>DN42 PingFinder</title>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <link href="/peers/assets/bootstrap.min.css" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
 | 
				
			||||||
 | 
					    <link href="/peers/assets/peerfinder.css" rel="stylesheet" integrity="sha384-ZsT4S9156eA60lsB4aOfffKowiaZ0NG7gIQfgIfGoxT6FxFocYH39kZgYaeZCvql"  crossorigin="anonymous">
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="container-fluid">
 | 
				
			||||||
 | 
					      <div class="header clearfix">
 | 
				
			||||||
 | 
					        <nav>
 | 
				
			||||||
 | 
					          <ul class="nav nav-pills pull-right">
 | 
				
			||||||
 | 
					            <li role="presentation"><a href="/peers">Home</a></li>
 | 
				
			||||||
 | 
					            <li role="presentation"><a href="/peers/status">Status</a></li>
 | 
				
			||||||
 | 
					            <li role="presentation"><a href="//util.sour.is/peer">Sign up/Manage</a></li>
 | 
				
			||||||
 | 
					            <li role="presentation"><a href="//git.dn42.us/dn42/pingfinder/src/master/clients">Scripts</a></li>
 | 
				
			||||||
 | 
					          </ul>
 | 
				
			||||||
 | 
					        </nav>
 | 
				
			||||||
 | 
					        <h3 class="text-muted">DN42 PeerFinder</h3>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class=container>
 | 
				
			||||||
 | 
						{{template "content" .}}
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class=container>
 | 
				
			||||||
 | 
					  <h2>JSON Output</h2>
 | 
				
			||||||
 | 
					  <pre style="background:#222; color:#ddd; height: 20em; font-size: 65%">{$o|json_encode:128|escape}</pre>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
 | 
					{{end}}
 | 
				
			||||||
							
								
								
									
										43
									
								
								app/peerfinder/pages/home.tpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								app/peerfinder/pages/home.tpl
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					{{template "main" .}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{define "meta"}}
 | 
				
			||||||
 | 
					    <meta http-equiv="refresh" content="30">
 | 
				
			||||||
 | 
					{{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{define "content"}}
 | 
				
			||||||
 | 
					  <h2>What is this?</h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <p>This tool allows you to find "good" peerings
 | 
				
			||||||
 | 
					  for <a href="https://dn42.net">dn42</a>, by measuring the latency from
 | 
				
			||||||
 | 
					  various points in the network towards you.</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <p>If you don't know what dn42 is,
 | 
				
			||||||
 | 
					  read <a href="https://dn42.net/Home">the website</a> and in particular
 | 
				
			||||||
 | 
					  the <a href="https://dn42.net/Getting-started-with-dn42">Getting Started
 | 
				
			||||||
 | 
					  guide</a>.</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <h2>How does it work?</h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <p>
 | 
				
			||||||
 | 
					    <ol>
 | 
				
			||||||
 | 
					      <li>You enter your (Internet) IP address</li>
 | 
				
			||||||
 | 
					      <li>Various routers participating in dn42 will ping you over the Internet</li>
 | 
				
			||||||
 | 
					      <li>After a short while, you get back all the latency results</li>
 | 
				
			||||||
 | 
					      <li>You can then peer with people close to you (low latency)</li>
 | 
				
			||||||
 | 
					    </ol>
 | 
				
			||||||
 | 
					  </p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <form class="form-inline" method="POST" action="/peers/req">
 | 
				
			||||||
 | 
					        <label>Ping IP Address [Check Hidden?]:</label>
 | 
				
			||||||
 | 
					        <div class="input-group input-group-sm">
 | 
				
			||||||
 | 
					            <input class="form-control" type="text" name="req_ip" placeholder="{$rq->remote_ip}">
 | 
				
			||||||
 | 
					            <span class="input-group-addon">
 | 
				
			||||||
 | 
					              <input type="checkbox" name="req_hidden" value=1 aria-label="Hidden?">
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <button class="btn btn-default" type="submit">Submit</button>
 | 
				
			||||||
 | 
					  </form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <p>If you mark your measurement as hidden, it will not be displayed on the
 | 
				
			||||||
 | 
					  page below.  Note that the IP addresses of the target will be shown alongside the result.</p>
 | 
				
			||||||
 | 
					{{end}}
 | 
				
			||||||
							
								
								
									
										121
									
								
								pkg/es/driver/resolve-links/resolve-links.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								pkg/es/driver/resolve-links/resolve-links.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
				
			|||||||
 | 
					package resolvelinks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/sour-is/ev/internal/lg"
 | 
				
			||||||
 | 
						"github.com/sour-is/ev/pkg/es"
 | 
				
			||||||
 | 
						"github.com/sour-is/ev/pkg/es/driver"
 | 
				
			||||||
 | 
						"github.com/sour-is/ev/pkg/es/event"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type resolvelinks struct {
 | 
				
			||||||
 | 
						up driver.Driver
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func New() *resolvelinks {
 | 
				
			||||||
 | 
						return &resolvelinks{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (r *resolvelinks) Apply(es *es.EventStore) {
 | 
				
			||||||
 | 
						r.up = es.Driver
 | 
				
			||||||
 | 
						es.Driver = r
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (r *resolvelinks) Unwrap() driver.Driver {
 | 
				
			||||||
 | 
						return r.up
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (r *resolvelinks) Open(ctx context.Context, dsn string) (driver.Driver, error) {
 | 
				
			||||||
 | 
						ctx, span := lg.Span(ctx)
 | 
				
			||||||
 | 
						defer span.End()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return r.up.Open(ctx, dsn)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *resolvelinks) EventLog(ctx context.Context, streamID string) (driver.EventLog, error) {
 | 
				
			||||||
 | 
						ctx, span := lg.Span(ctx)
 | 
				
			||||||
 | 
						defer span.End()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						l, err := r.up.EventLog(ctx, streamID)
 | 
				
			||||||
 | 
						return &wrapper{l, r}, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type wrapper struct {
 | 
				
			||||||
 | 
						up           driver.EventLog
 | 
				
			||||||
 | 
						resolvelinks *resolvelinks
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (w *wrapper) Read(ctx context.Context, after int64, count int64) (event.Events, error) {
 | 
				
			||||||
 | 
						ctx, span := lg.Span(ctx)
 | 
				
			||||||
 | 
						defer span.End()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						events, err := w.up.Read(ctx, after, count)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, e := range events {
 | 
				
			||||||
 | 
							switch e := e.(type) {
 | 
				
			||||||
 | 
							case *event.EventPtr:
 | 
				
			||||||
 | 
								d, err := w.resolvelinks.EventLog(ctx, e.StreamID)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								lis, err := d.ReadN(ctx, e.Pos)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								events[i] = lis.First()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return events, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (w *wrapper) ReadN(ctx context.Context, index ...uint64) (event.Events, error) {
 | 
				
			||||||
 | 
						ctx, span := lg.Span(ctx)
 | 
				
			||||||
 | 
						defer span.End()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						events, err := w.up.ReadN(ctx, index...)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, e := range events {
 | 
				
			||||||
 | 
							switch e := e.(type) {
 | 
				
			||||||
 | 
							case *event.EventPtr:
 | 
				
			||||||
 | 
								d, err := w.resolvelinks.EventLog(ctx, e.StreamID)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								lis, err := d.ReadN(ctx, e.Pos)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								events[i] = lis.First()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return events, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (w *wrapper) Append(ctx context.Context, events event.Events, version uint64) (uint64, error) {
 | 
				
			||||||
 | 
						ctx, span := lg.Span(ctx)
 | 
				
			||||||
 | 
						defer span.End()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return w.up.Append(ctx, events, version)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (w *wrapper) FirstIndex(ctx context.Context) (uint64, error) {
 | 
				
			||||||
 | 
						ctx, span := lg.Span(ctx)
 | 
				
			||||||
 | 
						defer span.End()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return w.up.FirstIndex(ctx)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (w *wrapper) LastIndex(ctx context.Context) (uint64, error) {
 | 
				
			||||||
 | 
						ctx, span := lg.Span(ctx)
 | 
				
			||||||
 | 
						defer span.End()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return w.up.LastIndex(ctx)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -137,7 +137,13 @@ func (m Meta) Created() time.Time {
 | 
				
			|||||||
func (m Meta) GetEventID() string { return m.EventID.String() }
 | 
					func (m Meta) GetEventID() string { return m.EventID.String() }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Init(ctx context.Context) error {
 | 
					func Init(ctx context.Context) error {
 | 
				
			||||||
	return Register(ctx, NilEvent, &EventPtr{})
 | 
						if err := Register(ctx, NilEvent, &EventPtr{}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := RegisterName(ctx, "event.eventPtr", &EventPtr{}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type nilEvent struct{}
 | 
					type nilEvent struct{}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user