Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 26 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ Tiros is an IPFS website measurement tool. It is intended to run on AWS ECS in m

## Table of Contents

- [Table of Contents](#table-of-contents)
- [Run](#run)
- [Development](#development)
- [Maintainers](#maintainers)
- [Contributing](#contributing)
- [License](#license)
- [Tiros](#tiros)
- [Table of Contents](#table-of-contents)
- [Measurement Methodology](#measurement-methodology)
- [Measurement Metrics](#measurement-metrics)
- [Run](#run)
- [Development](#development)
- [Migrations](#migrations)
- [Alternative IPFS Implementation](#alternative-ipfs-implementation)
- [Maintainers](#maintainers)
- [Contributing](#contributing)
- [License](#license)

## Measurement Methodology

Expand Down Expand Up @@ -44,11 +49,11 @@ var metricsStr string
rod.Try(func() {
browser = browser.Context(c.Context).MustIncognito() // first defense to prevent hitting the cache
browser.MustSetCookies() // second defense to prevent hitting the cache (empty args clears cookies)

page := browser.MustPage() // Get a handle of a new page in our incognito browser

page.MustEvalOnNewDocument(jsOnNewDocument) // third defense to prevent hitting the cache - clears the cache by running `localStorage.clear()`

// disable caching in general
proto.NetworkSetCacheDisabled{CacheDisabled: true}.Call(page) // fourth defense to prevent hitting the cache

Expand All @@ -63,7 +68,7 @@ rod.Try(func() {

// finally actually measure the stuff
metricsStr = page.MustEval(jsMeasurement).Str()

page.MustClose()
})
// parse metricsStr
Expand Down Expand Up @@ -185,7 +190,7 @@ for _, settle := range c.IntSlice("settle-times") {
for _, website := range websites {

pr, _ := t.Probe(c, websiteURL(c, website, mType))

t.Save(c, pr, website, mType, i)

if mType == models.MeasurementTypeIPFS {
Expand All @@ -208,24 +213,24 @@ https://developer.mozilla.org/en-US/docs/Learn/Performance/Perceived_performance
To quote the website:

> ## [Performance metrics](https://developer.mozilla.org/en-US/docs/Learn/Performance/Perceived_performance#performance_metrics)
>
>
> There is no single metric or test that can be run on a site to evaluate how a user "feels". However, there are a number of metrics that can be "helpful indicators":
>
>
> [First paint](https://developer.mozilla.org/en-US/docs/Glossary/First_paint)
> The time to start of first paint operation. Note that this change may not be visible; it can be a simple background color update or something even less noticeable.
>
>
> [First Contentful Paint](https://developer.mozilla.org/en-US/docs/Glossary/First_contentful_paint) (FCP)
> The time until first significant rendering (e.g. of text, foreground or background image, canvas or SVG, etc.). Note that this content is not necessarily useful or meaningful.
>
>
> [First Meaningful Paint](https://developer.mozilla.org/en-US/docs/Glossary/First_meaningful_paint) (FMP)
> The time at which useful content is rendered to the screen.
>
>
> [Largest Contentful Paint](https://wicg.github.io/largest-contentful-paint/) (LCP)
> The render time of the largest content element visible in the viewport.
>
>
> [Speed index](https://developer.mozilla.org/en-US/docs/Glossary/Speed_index)
> Measures the average time for pixels on the visible screen to be painted.
>
>
> [Time to interactive](https://developer.mozilla.org/en-US/docs/Glossary/Time_to_interactive)
> Time until the UI is available for user interaction (i.e. the last [long task](https://developer.mozilla.org/en-US/docs/Glossary/Long_task) of the load process finishes).

Expand Down Expand Up @@ -268,6 +273,7 @@ OPTIONS:
--db-sslmode value The sslmode to use when connecting the the database [$TIROS_RUN_DATABASE_SSL_MODE]
--kubo-api-port value port to reach the Kubo API (default: 5001) [$TIROS_RUN_KUBO_API_PORT]
--kubo-gateway-port value port to reach the Kubo Gateway (default: 8080) [$TIROS_RUN_KUBO_GATEWAY_PORT]
--chrome-host value port to reach the Chrome DevTools Protocol port (default: localhost) [$TIROS_RUN_CHROME_HOST]
--chrome-cdp-port value port to reach the Chrome DevTools Protocol port (default: 3000) [$TIROS_RUN_CHROME_CDP_PORT]
--cpu value CPU resources for this measurement run (default: 2) [$TIROS_RUN_CPU]
--memory value Memory resources for this measurement run (default: 4096) [$TIROS_RUN_MEMORY]
Expand All @@ -291,7 +297,8 @@ TIROS_RUN_DATABASE_PASSWORD=password
TIROS_RUN_DATABASE_PORT=5432
TIROS_RUN_DATABASE_SSL_MODE=disable
TIROS_RUN_DATABASE_USER=tiros_test
TIROS_RUN_KUBO_HOST=ipfs # necessary so that the chrome container can access kubo
TIROS_RUN_KUBO_HOST_IP=127.0.0.1 # necessary so that the chrome container can access kubo
TIROS_RUN_KUBO_HOST_NAME=ipfs # necessary so that the chrome container can access kubo
TIROS_RUN_REGION=local
TIROS_RUN_SETTLE_TIMES=5,5
TIROS_RUN_TIMES=2
Expand Down
18 changes: 15 additions & 3 deletions cmd_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,15 @@ var RunCommand = &cli.Command{
EnvVars: []string{"TIROS_RUN_DATABASE_SSL_MODE"},
},
&cli.StringFlag{
Name: "ipfs-host",
Name: "ipfs-host-ip",
Usage: "host at which to reach the IPFS Gateway",
EnvVars: []string{"TIROS_RUN_IPFS_HOST", "TIROS_RUN_KUBO_HOST" /* <- legacy */},
EnvVars: []string{"TIROS_RUN_IPFS_HOST_IP", "TIROS_RUN_KUBO_HOST_IP"},
Value: "127.0.0.1",
},
&cli.StringFlag{
Name: "ipfs-host-name",
Usage: "hostname at which to reach the IPFS Gateway",
EnvVars: []string{"TIROS_RUN_IPFS_HOST_NAME", "TIROS_RUN_KUBO_HOST_NAME"},
Value: "localhost",
},
&cli.IntFlag{
Expand All @@ -102,6 +108,12 @@ var RunCommand = &cli.Command{
EnvVars: []string{"TIROS_RUN_IPFS_GATEWAY_PORT", "TIROS_RUN_KUBO_GATEWAY_PORT" /* <- legacy */},
Value: 8080,
},
&cli.StringFlag{
Name: "chrome-host",
Usage: "port to reach the Chrome DevTools Host",
EnvVars: []string{"TIROS_RUN_CHROME_HOST"},
Value: "localhost",
},
&cli.IntFlag{
Name: "chrome-cdp-port",
Usage: "port to reach the Chrome DevTools Protocol port",
Expand Down Expand Up @@ -160,7 +172,7 @@ func RunAction(c *cli.Context) error {
// Initialize ipfs client
var ipfsClient *shell.Shell
if c.Int("ipfs-api-port") != 0 {
ipfsClient = shell.NewShell(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", c.Int("ipfs-api-port")))
ipfsClient = shell.NewShell(fmt.Sprintf("/ip4/%s/tcp/%d", c.String("ipfs-host-ip"), c.Int("ipfs-api-port")))
}

// Initialize maxmind client
Expand Down
84 changes: 84 additions & 0 deletions docker-compose.helia.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
version: "3.9"
name: tiros
networks:
tiros_net:
ipam:
config:
- subnet: 172.20.0.0/24

services:
# Inspired by: https://gist.github.com/NAR8789/92da076d0c35b434107fb4f4f198fd12
# https://hub.docker.com/r/4km3/dnsmasq
dnsmasq:
image: 4km3/dnsmasq:2.85-r2
command: -A /.helia/172.20.0.2
ports:
- 53:53/udp
cap_add:
- NET_ADMIN
networks:
tiros_net:
ipv4_address: 172.20.0.10 # Static IP here makes it possible to point other containers' dns here.

helia:
image: ghcr.io/ipfs/helia-http-gateway:main
restart: unless-stopped
ports:
- "8080:8080"
networks:
tiros_net:
ipv4_address: 172.20.0.2

chrome:
image: browserless/chrome:latest
ports:
- "3000:3000"
dns:
- 172.20.0.10
networks:
tiros_net:
ipv4_address: 172.20.0.3
db:
image: postgres:14
ports:
- "5432:5432"
environment:
POSTGRES_PASSWORD: password
POSTGRES_USER: tiros_test
POSTGRES_DB: tiros_test
networks:
tiros_net:
ipv4_address: 172.20.0.4

tiros:
image: golang:1.19
command: bash -c "cd /tiros && go run *.go run"
networks:
tiros_net:
ipv4_address: 172.20.0.5
dns:
- 172.20.0.10 # <- this is the dnsmasq container
volumes:
- .:/tiros
depends_on:
- db
- helia
- chrome
environment:
- TIROS_DEBUG=true
- TIROS_IPFS_IMPLEMENTATION=KUBO
- TIROS_RUN_CHROME_HOST=chrome
- TIROS_RUN_DATABASE_HOST=db
- TIROS_RUN_DATABASE_NAME=tiros_test
- TIROS_RUN_DATABASE_PASSWORD=password
- TIROS_RUN_DATABASE_PORT=5432
- TIROS_RUN_DATABASE_SSL_MODE=disable
- TIROS_RUN_DATABASE_USER=tiros_test
- TIROS_RUN_KUBO_API_PORT=8080
- TIROS_RUN_KUBO_HOST_IP=172.20.0.2
- TIROS_RUN_KUBO_HOST_NAME=helia
- TIROS_RUN_LOOKUP_PROVIDERS=false
- TIROS_RUN_REGION=local
- TIROS_RUN_SETTLE_TIMES=1 # <- set the first 1 to something larger to wait x number of seconds before the first request is made
- TIROS_RUN_TIMES=1
- TIROS_RUN_WEBSITES=probelab.io # <- you can add comma separated values here
6 changes: 4 additions & 2 deletions probe.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type probe struct {
url string
website string
mType string
chromeHost string
cdpPort int

browser *rod.Browser
Expand Down Expand Up @@ -132,6 +133,7 @@ func newProbe(c *cli.Context, website string, mType string) *probe {
url: websiteURL(c, website, mType),
website: website,
mType: mType,
chromeHost: c.String("chrome-host"),
cdpPort: c.Int("chrome-cdp-port"),
result: &probeResult{
url: websiteURL(c, website, mType),
Expand Down Expand Up @@ -176,7 +178,7 @@ func (p *probe) initBrowser() error {
// Initialize browser reference
p.browser = rod.New().
Context(p.ctx). // stop when outer ctx stops
ControlURL(fmt.Sprintf("ws://localhost:%d", p.cdpPort))
ControlURL(fmt.Sprintf("ws://%s:%d", p.chromeHost, p.cdpPort))

// Connecting to headless chrome
p.logEntry().Debugln("Connecting to browser...")
Expand Down Expand Up @@ -331,7 +333,7 @@ func (p *probe) close() {
func websiteURL(c *cli.Context, website string, mType string) string {
switch mType {
case models.MeasurementTypeIPFS:
return fmt.Sprintf("http://%s:%d/ipns/%s", c.String("ipfs-host"), c.Int("ipfs-gateway-port"), website)
return fmt.Sprintf("http://%s:%d/ipns/%s", c.String("ipfs-host-name"), c.Int("ipfs-gateway-port"), website)
case models.MeasurementTypeHTTP:
return fmt.Sprintf("https://%s", website)
default:
Expand Down