├── .codecov.yml ├── LICENSE ├── README_cache └── gfm │ ├── individ-dl_8a7ab87cb7ebf5117e6a6d28bb1320cf.rdb │ ├── individ-up_743fc211c1fdff724897ec1d539725a4.rdb │ ├── dl-speeed_1d12b072240ffc8a4a8f50df855a5647.rdb │ ├── dl-speeed_1d12b072240ffc8a4a8f50df855a5647.rdx │ ├── individ-dl_8a7ab87cb7ebf5117e6a6d28bb1320cf.rdx │ ├── individ-up_743fc211c1fdff724897ec1d539725a4.rdx │ ├── dl-speeed_1d12b072240ffc8a4a8f50df855a5647.RData │ ├── individ-dl_8a7ab87cb7ebf5117e6a6d28bb1320cf.RData │ ├── individ-up_743fc211c1fdff724897ec1d539725a4.RData │ ├── moar-dl-tests_cbe16607b1e0a73591b453bad2a1dcea.rdb │ ├── moar-dl-tests_cbe16607b1e0a73591b453bad2a1dcea.rdx │ ├── moar-ul-tests_e6806b1b4262d934cc062ee5bd8c6e9c.rdb │ ├── moar-ul-tests_e6806b1b4262d934cc062ee5bd8c6e9c.rdx │ ├── moar-dl-tests_cbe16607b1e0a73591b453bad2a1dcea.RData │ ├── moar-ul-tests_e6806b1b4262d934cc062ee5bd8c6e9c.RData │ └── __packages ├── .travis.yml ├── man ├── figures │ ├── spdtst.gif │ ├── README-moar-dl-tests-1.png │ └── README-moar-ul-tests-1.png ├── pipe.Rd ├── spd_config.Rd ├── install_speedtest_cli.Rd ├── spd_test.Rd ├── spd_servers.Rd ├── nice_speed.Rd ├── speedtest_cli.Rd ├── spd_compute_bandwidth.Rd ├── speedtest.Rd ├── spd_closest_servers.Rd ├── spd_best_servers.Rd ├── spd_upload_test.Rd └── spd_download_test.Rd ├── .gitignore ├── tests └── tinytest.R ├── CRAN-RELEASE ├── NEWS.md ├── R ├── utils-pipe.R ├── aaa.r ├── install-speedtest-cli.R ├── bandwidth.r ├── closest.r ├── speedtest-package.R ├── config.r ├── test-main.r ├── servers.r ├── util.r ├── speedtest-cli.R ├── bestest.r ├── upload.r └── download.r ├── inst └── tinytest │ └── test_speedtest.R ├── .Rbuildignore ├── speedtest.Rproj ├── cran-comments.md ├── Makefile ├── appveyor.yml ├── NAMESPACE ├── LICENSE.md ├── DESCRIPTION ├── CONDUCT.md ├── README.Rmd └── README.md /.codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2019 2 | COPYRIGHT HOLDER: Bob Rudis 3 | -------------------------------------------------------------------------------- /README_cache/gfm/individ-dl_8a7ab87cb7ebf5117e6a6d28bb1320cf.rdb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README_cache/gfm/individ-up_743fc211c1fdff724897ec1d539725a4.rdb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: R 2 | cache: packages 3 | after_success: 4 | - Rscript -e 'covr::codecov()' -------------------------------------------------------------------------------- /man/figures/spdtst.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/man/figures/spdtst.gif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .Rproj.user 3 | .Rhistory 4 | .RData 5 | .Rproj 6 | src/*.o 7 | src/*.so 8 | src/*.dll 9 | -------------------------------------------------------------------------------- /man/figures/README-moar-dl-tests-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/man/figures/README-moar-dl-tests-1.png -------------------------------------------------------------------------------- /man/figures/README-moar-ul-tests-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/man/figures/README-moar-ul-tests-1.png -------------------------------------------------------------------------------- /tests/tinytest.R: -------------------------------------------------------------------------------- 1 | 2 | if ( requireNamespace("tinytest", quietly=TRUE) ){ 3 | tinytest::test_package("speedtest") 4 | } 5 | 6 | -------------------------------------------------------------------------------- /CRAN-RELEASE: -------------------------------------------------------------------------------- 1 | This package was submitted to CRAN on 2019-07-24. 2 | Once it is accepted, delete this file and tag the release (commit 38718d8910). 3 | -------------------------------------------------------------------------------- /README_cache/gfm/dl-speeed_1d12b072240ffc8a4a8f50df855a5647.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/dl-speeed_1d12b072240ffc8a4a8f50df855a5647.rdb -------------------------------------------------------------------------------- /README_cache/gfm/dl-speeed_1d12b072240ffc8a4a8f50df855a5647.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/dl-speeed_1d12b072240ffc8a4a8f50df855a5647.rdx -------------------------------------------------------------------------------- /README_cache/gfm/individ-dl_8a7ab87cb7ebf5117e6a6d28bb1320cf.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/individ-dl_8a7ab87cb7ebf5117e6a6d28bb1320cf.rdx -------------------------------------------------------------------------------- /README_cache/gfm/individ-up_743fc211c1fdff724897ec1d539725a4.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/individ-up_743fc211c1fdff724897ec1d539725a4.rdx -------------------------------------------------------------------------------- /README_cache/gfm/dl-speeed_1d12b072240ffc8a4a8f50df855a5647.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/dl-speeed_1d12b072240ffc8a4a8f50df855a5647.RData -------------------------------------------------------------------------------- /README_cache/gfm/individ-dl_8a7ab87cb7ebf5117e6a6d28bb1320cf.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/individ-dl_8a7ab87cb7ebf5117e6a6d28bb1320cf.RData -------------------------------------------------------------------------------- /README_cache/gfm/individ-up_743fc211c1fdff724897ec1d539725a4.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/individ-up_743fc211c1fdff724897ec1d539725a4.RData -------------------------------------------------------------------------------- /README_cache/gfm/moar-dl-tests_cbe16607b1e0a73591b453bad2a1dcea.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/moar-dl-tests_cbe16607b1e0a73591b453bad2a1dcea.rdb -------------------------------------------------------------------------------- /README_cache/gfm/moar-dl-tests_cbe16607b1e0a73591b453bad2a1dcea.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/moar-dl-tests_cbe16607b1e0a73591b453bad2a1dcea.rdx -------------------------------------------------------------------------------- /README_cache/gfm/moar-ul-tests_e6806b1b4262d934cc062ee5bd8c6e9c.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/moar-ul-tests_e6806b1b4262d934cc062ee5bd8c6e9c.rdb -------------------------------------------------------------------------------- /README_cache/gfm/moar-ul-tests_e6806b1b4262d934cc062ee5bd8c6e9c.rdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/moar-ul-tests_e6806b1b4262d934cc062ee5bd8c6e9c.rdx -------------------------------------------------------------------------------- /README_cache/gfm/moar-dl-tests_cbe16607b1e0a73591b453bad2a1dcea.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/moar-dl-tests_cbe16607b1e0a73591b453bad2a1dcea.RData -------------------------------------------------------------------------------- /README_cache/gfm/moar-ul-tests_e6806b1b4262d934cc062ee5bd8c6e9c.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrbrmstr/speedtest/HEAD/README_cache/gfm/moar-ul-tests_e6806b1b4262d934cc062ee5bd8c6e9c.RData -------------------------------------------------------------------------------- /README_cache/gfm/__packages: -------------------------------------------------------------------------------- 1 | base 2 | speedtest 3 | stringi 4 | hrbrthemes 5 | ggplot2 6 | ggbeeswarm 7 | tidyverse 8 | tibble 9 | tidyr 10 | readr 11 | purrr 12 | dplyr 13 | stringr 14 | forcats 15 | bit 16 | bit64 17 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | 0.2.0 2 | * Updated pkg infrastructure (non-salient to operations) 3 | * Now passes CRAN checks 4 | * Updated user agent 5 | * Ensured primary URLs for speedtest resources are HTTPS 6 | * Swiched to {tinytest} 7 | 8 | 0.1.0 9 | * Initial release 10 | -------------------------------------------------------------------------------- /R/utils-pipe.R: -------------------------------------------------------------------------------- 1 | #' Pipe operator 2 | #' 3 | #' See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. 4 | #' 5 | #' @name %>% 6 | #' @rdname pipe 7 | #' @keywords internal 8 | #' @export 9 | #' @importFrom magrittr %>% 10 | #' @usage lhs \%>\% rhs 11 | NULL 12 | -------------------------------------------------------------------------------- /inst/tinytest/test_speedtest.R: -------------------------------------------------------------------------------- 1 | library(speedtest) 2 | 3 | # speeds are displayed in appropriate units 4 | expect_true(grepl("Kbit/s", nice_speed(0.1))) 5 | expect_true(grepl("Mbit/s", nice_speed(1))) 6 | expect_true(grepl("Gbit/s", nice_speed(1000))) 7 | 8 | expect_true(all(c("client", "odometer") %in% names(spd_config()))) 9 | -------------------------------------------------------------------------------- /man/pipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-pipe.R 3 | \name{\%>\%} 4 | \alias{\%>\%} 5 | \title{Pipe operator} 6 | \usage{ 7 | lhs \%>\% rhs 8 | } 9 | \description{ 10 | See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^\.travis\.yml$ 4 | ^README\.*Rmd$ 5 | ^README\.*html$ 6 | ^NOTES\.*Rmd$ 7 | ^NOTES\.*html$ 8 | ^README\.gfm*$ 9 | ^README_cache$ 10 | ^\.codecov\.yml$ 11 | ^README_files$ 12 | ^doc$ 13 | ^CONDUCT\.md$ 14 | ^imgs$ 15 | ^LICENSE\.md$ 16 | ^Makefile$ 17 | ^appveyor\.yml$ 18 | 19 | ^cran-comments\.md$ 20 | ^CRAN-RELEASE$ 21 | -------------------------------------------------------------------------------- /man/spd_config.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/config.r 3 | \name{spd_config} 4 | \alias{spd_config} 5 | \title{Retrieve client configuration information for the speedtest} 6 | \usage{ 7 | spd_config() 8 | } 9 | \description{ 10 | Retrieve client configuration information for the speedtest 11 | } 12 | \examples{ 13 | \dontrun{ 14 | spd_config() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /man/install_speedtest_cli.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/install-speedtest-cli.R 3 | \name{install_speedtest_cli} 4 | \alias{install_speedtest_cli} 5 | \title{Provides instructions for installing the official speedtest CLI application} 6 | \usage{ 7 | install_speedtest_cli() 8 | } 9 | \description{ 10 | Provides instructions for installing the official speedtest CLI application 11 | } 12 | -------------------------------------------------------------------------------- /R/aaa.r: -------------------------------------------------------------------------------- 1 | .base_raw <- charToRaw('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ') 2 | 3 | .speedtest_ua <- "Mozilla/5.0 (Compatible; r-speedtest/1.0; https://gitlab.com/hrbrmstr/speedtest)" 4 | 5 | utils::globalVariables( 6 | c( 7 | "total", "latency_url", "test_result", "ping_time", "total_time", 8 | "retrieval_time", "bw", "size", "secs", "id" 9 | ) 10 | ) 11 | 12 | sGET <- purrr::safely(httr::GET) 13 | sPOST <- purrr::safely(httr::POST) 14 | -------------------------------------------------------------------------------- /R/install-speedtest-cli.R: -------------------------------------------------------------------------------- 1 | #' Provides instructions for installing the official speedtest CLI application 2 | #' 3 | #' @export 4 | install_speedtest_cli <- function() { 5 | 6 | utils::browseURL("https://www.speedtest.net/apps/cli") 7 | 8 | warning( 9 | "You will need to run speedtest once manually so you ", 10 | "can accept the Ookla license. Failure to do so will ", 11 | "result in errors generated by the use of speedtest_cli().", 12 | call. = FALSE 13 | ) 14 | 15 | } -------------------------------------------------------------------------------- /speedtest.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | StripTrailingWhitespace: Yes 16 | 17 | BuildType: Package 18 | PackageUseDevtools: Yes 19 | PackageInstallArgs: --no-multiarch --with-keep.source 20 | PackageBuildArgs: --resave-data 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /R/bandwidth.r: -------------------------------------------------------------------------------- 1 | #' Compute bandwidth from bytes transferred and time taken 2 | #' 3 | #' @md 4 | #' @param size_bytes size (in bytes) of the payload transferred 5 | #' @param xfer_secs time taken for the transfer 6 | #' @param mbits produce output in megabits (Mb)? Default: `TRUE` 7 | #' @export 8 | #' @examples 9 | #' spd_compute_bandwidth(19200000, 1) # 150 Mb/sec 10 | spd_compute_bandwidth <- function(size_bytes, xfer_secs, mbits=TRUE) { 11 | res <- size_bytes / xfer_secs 12 | if (mbits) res <- (res*8) / 1024 / 1000 13 | res 14 | } 15 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Test environments 2 | * local OS X install, R 3.6.1 3 | * ubuntu 14.04 (on travis-ci), R 3.6.1 4 | * win-builder (devel and release) 5 | 6 | ## R CMD check results 7 | 8 | 0 errors | 0 warnings | 1 note 9 | 10 | * This is a new release. 11 | 12 | -------------------- 13 | 14 | Nothing was flagged in winbuilder(s) so shld hopefully 15 | work on the CRAN pre-test infra. 16 | 17 | There is one live test requiring network connectivbity to 18 | retrieve a config from speedtest & verify the results. 19 | I can remove that if desired. 20 | -------------------------------------------------------------------------------- /man/spd_test.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/test-main.r 3 | \name{spd_test} 4 | \alias{spd_test} 5 | \title{Test your internet speed/bandwidth} 6 | \usage{ 7 | spd_test() 8 | } 9 | \description{ 10 | No-frills. Picks the closest geographic server with least latency, 11 | performs download & upload tests and returs the best result. 12 | } 13 | \details{ 14 | Make a command-line alias or executable with: 15 | 16 | \verb{Rscript --quiet -e 'speedtest::spd_test()'} 17 | } 18 | \examples{ 19 | \dontrun{ 20 | spd_test() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /man/spd_servers.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/servers.r 3 | \name{spd_servers} 4 | \alias{spd_servers} 5 | \title{Retrieve a list of SpeedTest servers} 6 | \usage{ 7 | spd_servers(config = NULL) 8 | } 9 | \arguments{ 10 | \item{config}{client configuration retrieved via \code{\link[=spd_config]{spd_config()}}. If \code{NULL} it 11 | will be retrieved} 12 | } 13 | \value{ 14 | data frame 15 | } 16 | \description{ 17 | Retrieve a list of SpeedTest servers 18 | } 19 | \examples{ 20 | \dontrun{ 21 | config <- spd_config() 22 | spd_servers(config) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /man/nice_speed.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/util.r 3 | \name{nice_speed} 4 | \alias{nice_speed} 5 | \title{Convert a test speed, in Mbits/s, to its string representation along with 6 | appropriate units for the magnitude of the test speed} 7 | \usage{ 8 | nice_speed(number) 9 | } 10 | \arguments{ 11 | \item{number}{numeric The speed to be converted} 12 | } 13 | \value{ 14 | character The character representation of the speed 15 | } 16 | \description{ 17 | - Assumes number is in Mbits/s to start off with 18 | - Only chooses between Kbit/s, Mbit/s, and Gbit/s 19 | } 20 | -------------------------------------------------------------------------------- /man/speedtest_cli.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/speedtest-cli.R 3 | \name{speedtest_cli} 4 | \alias{speedtest_cli} 5 | \alias{print.speedtest_cli_result} 6 | \title{Perform an official Ookla Speed Test via their command line tools} 7 | \usage{ 8 | speedtest_cli(progress = TRUE) 9 | 10 | \method{print}{speedtest_cli_result}(x, browse = FALSE, ...) 11 | } 12 | \arguments{ 13 | \item{x}{`speedtest_cli_result` object} 14 | 15 | \item{browse}{if `TRUE`, open a browser window with the results} 16 | 17 | \item{...}{ignored} 18 | } 19 | \description{ 20 | Perform an official Ookla Speed Test via their command line tools 21 | } 22 | -------------------------------------------------------------------------------- /man/spd_compute_bandwidth.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bandwidth.r 3 | \name{spd_compute_bandwidth} 4 | \alias{spd_compute_bandwidth} 5 | \title{Compute bandwidth from bytes transferred and time taken} 6 | \usage{ 7 | spd_compute_bandwidth(size_bytes, xfer_secs, mbits = TRUE) 8 | } 9 | \arguments{ 10 | \item{size_bytes}{size (in bytes) of the payload transferred} 11 | 12 | \item{xfer_secs}{time taken for the transfer} 13 | 14 | \item{mbits}{produce output in megabits (Mb)? Default: \code{TRUE}} 15 | } 16 | \description{ 17 | Compute bandwidth from bytes transferred and time taken 18 | } 19 | \examples{ 20 | spd_compute_bandwidth(19200000, 1) # 150 Mb/sec 21 | } 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PACKAGE := $(shell grep '^Package:' DESCRIPTION | sed -E 's/^Package:[[:space:]]+//') 2 | RSCRIPT = Rscript --no-init-file 3 | 4 | all: install 5 | 6 | test: 7 | ${RSCRIPT} -e 'library(methods); devtools::test()' 8 | 9 | doc: 10 | ${RSCRIPT} -e "library(methods); devtools::document()" 11 | 12 | install: 13 | ${RSCRIPT} -e "library(methods); devtools::install()" 14 | 15 | build: 16 | ${RSCRIPT} -e "library(methods); devtools::build()" 17 | 18 | check: 19 | _R_CHECK_CRAN_INCOMING_=FALSE make check_all 20 | 21 | check_all: 22 | ${RSCRIPT} -e "library(methods); devtools::check(cran=TRUE)" 23 | 24 | README.md: README.Rmd 25 | Rscript -e 'library(methods); devtools::load_all(); rmarkdown::render("README.Rmd", output_file="README.md")' 26 | sed -i.bak 's/[[:space:]]*$$//' $@ 27 | rm -f $@.bak 28 | 29 | .PHONY: all test doc install check check_all 30 | -------------------------------------------------------------------------------- /man/speedtest.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/speedtest-package.R 3 | \docType{package} 4 | \name{speedtest} 5 | \alias{speedtest} 6 | \alias{speedtest-package} 7 | \title{Tools to Test and Compare Internet Bandwidth Speeds} 8 | \description{ 9 | The 'Ookla' 'Speedtest' site \url{https://beta.speedtest.net/about} provides 10 | interactive and programmatic services to test and compare bandwidth speeds 11 | from a source node on the Internet to thousands of test servers. Tools are 12 | provided to obtain test server lists, identify target servers for testing and 13 | performing speed/bandwidth tests. 14 | } 15 | \seealso{ 16 | Useful links: 17 | \itemize{ 18 | \item \url{https://gitlab.com/hrbrmstr/speedtest} 19 | \item Report bugs at \url{https://gitlab.com/hrbrmstr/speedtest/issues} 20 | } 21 | 22 | } 23 | \author{ 24 | Bob Rudis (bob@rud.is) 25 | } 26 | -------------------------------------------------------------------------------- /man/spd_closest_servers.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/closest.r 3 | \name{spd_closest_servers} 4 | \alias{spd_closest_servers} 5 | \title{Find "closest" servers (geography-wise) from master server list} 6 | \usage{ 7 | spd_closest_servers(servers = NULL, config = NULL) 8 | } 9 | \arguments{ 10 | \item{servers}{if not \code{NULL}, then the data frame from \code{\link[=spd_servers]{spd_servers()}}. If 11 | \code{NULL}, then \code{\link[=spd_servers]{spd_servers()}} will be called to retrieve the server list.} 12 | 13 | \item{config}{client configuration retrieved via \code{\link[=spd_config]{spd_config()}}. If \code{NULL} it 14 | will be retrieved} 15 | } 16 | \value{ 17 | server list in order of geographic closeness 18 | } 19 | \description{ 20 | Find "closest" servers (geography-wise) from master server list 21 | } 22 | \examples{ 23 | \dontrun{ 24 | spd_closest_servers() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /R/closest.r: -------------------------------------------------------------------------------- 1 | #' Find "closest" servers (geography-wise) from master server list 2 | #' 3 | #' @md 4 | #' @param servers if not `NULL`, then the data frame from [spd_servers()]. If 5 | #' `NULL`, then [spd_servers()] will be called to retrieve the server list. 6 | #' @param config client configuration retrieved via [spd_config()]. If `NULL` it 7 | #' will be retrieved 8 | #' @return server list in order of geographic closeness 9 | #' @export 10 | #' @examples \dontrun{ 11 | #' spd_closest_servers() 12 | #' } 13 | spd_closest_servers <- function(servers=NULL, config=NULL) { 14 | 15 | if (is.null(config)) config <- spd_config() 16 | 17 | if (is.null(servers)) servers <- spd_servers(config) 18 | 19 | # we don't need great circle for this, just best effort 20 | idx <- order(sqrt((servers$lat - as.numeric(config$client$lat))^2 + 21 | (servers$lng - as.numeric(config$client$lon))^2)) 22 | 23 | servers[idx,] 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /R/speedtest-package.R: -------------------------------------------------------------------------------- 1 | #' Tools to Test and Compare Internet Bandwidth Speeds 2 | #' 3 | #' The 'Ookla' 'Speedtest' site provides 4 | #' interactive and programmatic services to test and compare bandwidth speeds 5 | #' from a source node on the Internet to thousands of test servers. Tools are 6 | #' provided to obtain test server lists, identify target servers for testing and 7 | #' performing speed/bandwidth tests. 8 | #' 9 | #' @md 10 | #' @name speedtest 11 | #' @docType package 12 | #' @author Bob Rudis (bob@@rud.is) 13 | #' @import purrr xml2 httr cli crayon 14 | #' @importFrom utils globalVariables browseURL 15 | #' @importFrom tibble tibble 16 | #' @importFrom dplyr left_join arrange filter select summarise mutate 17 | #' @importFrom jsonlite fromJSON 18 | #' @importFrom curl curl_fetch_multi multi_run 19 | #' @importFrom pingr ping 20 | #' @importFrom urltools domain 21 | #' @importFrom stats median sd 22 | #' @importFrom scales label_number_si 23 | "_PACKAGE" 24 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | 3 | # Download script file from GitHub 4 | init: 5 | ps: | 6 | $ErrorActionPreference = "Stop" 7 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 8 | Import-Module '..\appveyor-tool.ps1' 9 | 10 | install: 11 | ps: Bootstrap 12 | 13 | cache: 14 | - C:\RLibrary 15 | 16 | # Adapt as necessary starting from here 17 | 18 | build_script: 19 | - travis-tool.sh install_deps 20 | 21 | test_script: 22 | - travis-tool.sh run_tests 23 | 24 | on_failure: 25 | - 7z a failure.zip *.Rcheck\* 26 | - appveyor PushArtifact failure.zip 27 | 28 | artifacts: 29 | - path: '*.Rcheck\**\*.log' 30 | name: Logs 31 | 32 | - path: '*.Rcheck\**\*.out' 33 | name: Logs 34 | 35 | - path: '*.Rcheck\**\*.fail' 36 | name: Logs 37 | 38 | - path: '*.Rcheck\**\*.Rout' 39 | name: Logs 40 | 41 | - path: '\*_*.tar.gz' 42 | name: Bits 43 | 44 | - path: '\*_*.zip' 45 | name: Bits 46 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(print,speedtest_cli_result) 4 | export("%>%") 5 | export(install_speedtest_cli) 6 | export(nice_speed) 7 | export(spd_best_servers) 8 | export(spd_closest_servers) 9 | export(spd_compute_bandwidth) 10 | export(spd_config) 11 | export(spd_download_test) 12 | export(spd_servers) 13 | export(spd_test) 14 | export(spd_upload_test) 15 | export(speedtest_cli) 16 | import(cli) 17 | import(crayon) 18 | import(httr) 19 | import(purrr) 20 | import(xml2) 21 | importFrom(curl,curl_fetch_multi) 22 | importFrom(curl,multi_run) 23 | importFrom(dplyr,arrange) 24 | importFrom(dplyr,filter) 25 | importFrom(dplyr,left_join) 26 | importFrom(dplyr,mutate) 27 | importFrom(dplyr,select) 28 | importFrom(dplyr,summarise) 29 | importFrom(jsonlite,fromJSON) 30 | importFrom(magrittr,"%>%") 31 | importFrom(pingr,ping) 32 | importFrom(scales,label_number_si) 33 | importFrom(stats,median) 34 | importFrom(stats,sd) 35 | importFrom(tibble,tibble) 36 | importFrom(urltools,domain) 37 | importFrom(utils,browseURL) 38 | importFrom(utils,globalVariables) 39 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2019 Bob Rudis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /R/config.r: -------------------------------------------------------------------------------- 1 | #' Retrieve client configuration information for the speedtest 2 | #' 3 | #' @md 4 | #' @export 5 | #' @examples \dontrun{ 6 | #' spd_config() 7 | #' } 8 | spd_config <- function() { 9 | 10 | httr::GET( 11 | url = "https://www.speedtest.net/speedtest-config.php", 12 | httr::user_agent(.speedtest_ua) 13 | ) -> res 14 | 15 | httr::stop_for_status(res) 16 | 17 | config <- httr::content(res, as="text", encoding="UTF-8") 18 | config <- xml2::read_xml(config) 19 | config <- xml2::as_list(config) 20 | config <- config$settings 21 | config <- purrr::map(config, function(.x) { c(.x, attributes(.x)) }) 22 | config$`server-config`$ignoreids <- strsplit(config$`server-config`$ignoreids, ",")[[1]] 23 | 24 | sz <- as.numeric(gsub("[^[:digit:]]", "", config$upload$mintestsize)) 25 | 26 | if (grepl("[^[:digit:]]", config$upload$mintestsize)) { 27 | up_units <- gsub("[[:digit:]]", "", config$upload$mintestsize) 28 | sz <- as.numeric(gsub("[^[:digit:]]", "", config$upload$mintestsize)) 29 | sz <- sz * switch(up_units, K=1024, M=1024000) 30 | } 31 | 32 | config$upload$mintestsize <- sz 33 | 34 | config 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: speedtest 2 | Type: Package 3 | Title: Tools to Test and Compare Internet Bandwidth Speeds 4 | Version: 0.3.0 5 | Date: 2020-03-19 6 | Authors@R: c( person("Bob", "Rudis", email = "bob@rud.is", 7 | role = c("aut", "cre"), comment = c(ORCID = 8 | "0000-0001-5670-2640")), person("Bryce", "Mecum", 9 | email = "petridish@gmail.com", role = "ctb", comment 10 | = c(ORCID = "0000-0002-0381-3766")), 11 | person("Garrett", "Mooney", email = 12 | "gmooney@mail.bradley.edu", role = "ctb") ) 13 | Maintainer: Bob Rudis 14 | Description: The 'Ookla' 'Speedtest' site 15 | provides 16 | interactive and programmatic services to test and 17 | compare bandwidth speeds from a source node on the 18 | Internet to thousands of test servers. Tools are 19 | provided to obtain test server lists, identify target 20 | servers for testing and performing speed/bandwidth 21 | tests. 22 | URL: https://gitlab.com/hrbrmstr/speedtest 23 | BugReports: https://gitlab.com/hrbrmstr/speedtest/issues 24 | License: MIT + file LICENSE 25 | Suggests: covr, tinytest 26 | Depends: R (>= 3.2.0) 27 | Encoding: UTF-8 28 | Imports: httr, stats, curl, purrr, dplyr, xml2, utils, 29 | pingr, urltools, jsonlite, crayon, tibble, cli, 30 | magrittr 31 | RoxygenNote: 7.0.2 32 | -------------------------------------------------------------------------------- /CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who 4 | contribute through reporting issues, posting feature requests, updating documentation, 5 | submitting pull requests or patches, and other activities. 6 | 7 | We are committed to making participation in this project a harassment-free experience for 8 | everyone, regardless of level of experience, gender, gender identity and expression, 9 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 10 | 11 | Examples of unacceptable behavior by participants include the use of sexual language or 12 | imagery, derogatory comments or personal attacks, trolling, public or private harassment, 13 | insults, or other unprofessional conduct. 14 | 15 | Project maintainers have the right and responsibility to remove, edit, or reject comments, 16 | commits, code, wiki edits, issues, and other contributions that are not aligned to this 17 | Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed 18 | from the project team. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by 21 | opening an issue or contacting one or more of the project maintainers. 22 | 23 | This Code of Conduct is adapted from the Contributor Covenant 24 | (http:contributor-covenant.org), version 1.0.0, available at 25 | http://contributor-covenant.org/version/1/0/0/ 26 | -------------------------------------------------------------------------------- /R/test-main.r: -------------------------------------------------------------------------------- 1 | #' Test your internet speed/bandwidth 2 | #' 3 | #' No-frills. Picks the closest geographic server with least latency, 4 | #' performs download & upload tests and returs the best result. 5 | #' 6 | #' Make a command-line alias or executable with: 7 | #' 8 | #' `Rscript --quiet -e 'speedtest::spd_test()'` 9 | #' 10 | #' @md 11 | #' @export 12 | #' @examples \dontrun{ 13 | #' spd_test() 14 | #' } 15 | spd_test <- function() { 16 | 17 | cat(cyan("Gathering test configuration information...\n")) 18 | config <- spd_config() 19 | 20 | cat(cyan("Gathering server list...\n")) 21 | servers <- spd_servers(config=config) 22 | 23 | cat(cyan("Determining best server...\n")) 24 | servers <- spd_closest_servers(servers, config) 25 | # best <- servers 26 | best <- spd_best_servers(servers, config, max=3) 27 | 28 | cat( 29 | green("Initiating test from ") %+% white(config$client$isp) %+% green(" (") %+% 30 | white(config$client$ip) %+% green(") to ") %+% white(best$sponsor[1]) %+% 31 | green(" (") %+% white(best$name[1]) %+% green(")\n\n") 32 | ) 33 | 34 | cat(white$bold("Analyzing download speed")) 35 | down <- spd_download_test(best, config, FALSE, timeout = 5, .progress = "dots") 36 | 37 | cat(green("Download: ") %+% white$bold(nice_speed(max(down$bw))) %+% "\n") 38 | 39 | cat(white$bold("\nAnalyzing upload speed")) 40 | up <- spd_upload_test(best, config, FALSE, timeout=10, .progress="dots") 41 | 42 | cat(green("Upload: ") %+% white$bold(nice_speed(max(up$bw))) %+% "\n") 43 | 44 | } 45 | -------------------------------------------------------------------------------- /man/spd_best_servers.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bestest.r 3 | \name{spd_best_servers} 4 | \alias{spd_best_servers} 5 | \title{Find "best" servers (latency-wise) from master server list} 6 | \usage{ 7 | spd_best_servers(servers = NULL, config = NULL, max = 10) 8 | } 9 | \arguments{ 10 | \item{servers}{if not \code{NULL}, then the data frame from \code{\link[=spd_servers]{spd_servers()}}. If 11 | \code{NULL}, then \code{\link[=spd_servers]{spd_servers()}} will be called to retrieve the server list.} 12 | 13 | \item{config}{client configuration retrieved via \code{\link[=spd_config]{spd_config()}}. If \code{NULL} it 14 | will be retrieved} 15 | 16 | \item{max}{the maximum numbers of "best" servers to return. This is hard-capped 17 | at 25 since Oookla is a free/sponsored service and if you plan on abusing 18 | it you'll have to write your own code to do so. Default is \code{10}.} 19 | } 20 | \value{ 21 | server list in order of latency closeness (retrieval speed column included) 22 | } 23 | \description{ 24 | The input \code{servers} data frame will be truncatred to the first \code{max} and 25 | HTTP and ICMP probe tests will be performed to determine initial retrieval 26 | speed and latency. Not all servers respond to ICMP requests due to the way 27 | their routers, switches or firewalls are configured. 28 | } 29 | \note{ 30 | the list of target servers will be truncated to the first \code{max}. \code{max} may 31 | amount may not be returned if there were errors connecting to servers. 32 | } 33 | -------------------------------------------------------------------------------- /R/servers.r: -------------------------------------------------------------------------------- 1 | #' Retrieve a list of SpeedTest servers 2 | #' 3 | #' @md 4 | #' @param config client configuration retrieved via [spd_config()]. If `NULL` it 5 | #' will be retrieved 6 | #' @return data frame 7 | #' @export 8 | #' @examples \dontrun{ 9 | #' config <- spd_config() 10 | #' spd_servers(config) 11 | #' } 12 | spd_servers <- function(config=NULL) { 13 | 14 | httr::GET( 15 | url = "https://www.speedtest.net/speedtest-servers-static.php", 16 | httr::user_agent(.speedtest_ua) 17 | ) -> res 18 | 19 | httr::stop_for_status(res) 20 | 21 | if (is.null(config)) config <- spd_config() 22 | 23 | httr::content(res, as = "text", encoding = "UTF-8") %>% 24 | xml2::read_xml() %>% 25 | xml2::xml_find_all(xpath = "//settings/servers/server") %>% 26 | purrr::map_df(~{ 27 | list( 28 | url = xml2::xml_attr(.x, "url") %||% NA_character_, 29 | lat = as.numeric(xml2::xml_attr(.x, "lat") %||% NA_real_), 30 | lng = as.numeric(xml2::xml_attr(.x, "lon")) %||% NA_real_, 31 | name = xml2::xml_attr(.x, "name") %||% NA_character_, 32 | country = xml2::xml_attr(.x, "country") %||% NA_character_, 33 | cc = xml2::xml_attr(.x, "cc") %||% NA_character_, 34 | sponsor = xml2::xml_attr(.x, "sponsor") %||% NA_character_, 35 | id = xml2::xml_attr(.x, "id") %||% NA_character_, 36 | host = xml2::xml_attr(.x, "host") %||% NA_character_, 37 | url2 = xml2::xml_attr(.x, "url2") %||% NA_character_ 38 | ) 39 | }) %>% 40 | dplyr::filter(!(id %in% config$`server-config`$ignoreids)) 41 | 42 | } 43 | -------------------------------------------------------------------------------- /R/util.r: -------------------------------------------------------------------------------- 1 | .download_one <- function(url, timeout) { 2 | sGET( 3 | url = url, 4 | httr::add_headers( 5 | `Referer` = "https://c.speedtest.net/flash/speedtest.swf", 6 | `Cache-Control` = "no-cache" # try to bust transparent proxy caches 7 | ), 8 | httr::user_agent(.speedtest_ua), 9 | httr::timeout(timeout), 10 | query = list(ts = as.numeric(Sys.time())) # try to bust transparent proxy caches 11 | ) 12 | } 13 | 14 | .upload_one <- function(url, dat, timeout) { 15 | sPOST( 16 | url = url, 17 | httr::add_headers( 18 | `Referer` = "https://c.speedtest.net/flash/speedtest.swf", 19 | `Connection` = "Keep-Alive", 20 | `Cache-Control` = "no-cache" # try to bust transparent proxy caches 21 | ), 22 | encode="form", 23 | body = dat, 24 | httr::user_agent(.speedtest_ua), 25 | httr::timeout(timeout), 26 | query = list(ts = as.numeric(Sys.time())) # try to bust transparent proxy caches 27 | ) 28 | } 29 | 30 | #' Convert a test speed, in Mbits/s, to its string representation along with 31 | #' appropriate units for the magnitude of the test speed 32 | #' 33 | #' - Assumes number is in Mbits/s to start off with 34 | #' - Only chooses between Kbit/s, Mbit/s, and Gbit/s 35 | #' 36 | #' @param number numeric The speed to be converted 37 | #' @export 38 | #' @return character The character representation of the speed 39 | nice_speed <- function(number) { 40 | if (number < 1) { 41 | return(as.character(as.integer(number * 1000)) %+% " Kbit/s") 42 | } else if (number >= 1000) { 43 | return(as.character(as.integer(number / 1000)) %+% " Gbit/s") 44 | } else { 45 | return(as.character(as.integer(number)) %+% " Mbit/s") 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /man/spd_upload_test.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/upload.r 3 | \name{spd_upload_test} 4 | \alias{spd_upload_test} 5 | \title{Perform an upload speed/bandwidth test} 6 | \usage{ 7 | spd_upload_test( 8 | server, 9 | config = NULL, 10 | summarise = TRUE, 11 | timeout = 60, 12 | .progress = "dplyr" 13 | ) 14 | } 15 | \arguments{ 16 | \item{server}{a data frame row from one of the functions that retrieves or 17 | filters a server list. You can pass in a full servers list but 18 | only the first entry will be processed.} 19 | 20 | \item{config}{client configuration retrieved via \code{\link[=spd_config]{spd_config()}}. If \code{NULL} it 21 | will be retrieved} 22 | 23 | \item{summarise}{the raw results from each test --- including file sizes --- 24 | will be returned if the value is \code{FALSE}. If \code{TRUE} only summary 25 | statistics will be returned.} 26 | 27 | \item{timeout}{max time (seconds) to wait for a connection or download to finish. 28 | Default is \code{60} seconds} 29 | 30 | \item{.progress}{if "\code{dplyr}" then \code{dplyr} progress bars will be used. If 31 | "\code{dot}" then "\code{.}" will be used. If anything else or "\code{none}", then 32 | no progress will be reported.} 33 | } 34 | \description{ 35 | Currently, six tests are performed in increasing order of size. 36 | } 37 | \details{ 38 | This uses the legacy HTTP method of determining your bandwidth/speed and, 39 | as such, has many issues. Rather than hack-compensate for error-prone 40 | results with smaller files used on high-bandwidth connections, raw size + 41 | transfer speed data is returned enabling you to perform your own adjustments 42 | or choose which values to "believe". 43 | } 44 | \note{ 45 | speed/bandwidth values are in Mbits/s; these tests consume bandwidth so 46 | if you're on a metered connection, you may incur charges. 47 | } 48 | -------------------------------------------------------------------------------- /R/speedtest-cli.R: -------------------------------------------------------------------------------- 1 | #' Perform an official Ookla Speed Test via their command line tools 2 | #' 3 | #' @export 4 | speedtest_cli <- function(progress = TRUE) { 5 | 6 | spdtst <- Sys.which(c("speedtest", "speedtest.exe")) 7 | spdtst <- spdtst[spdtst != ""] 8 | 9 | if (length(spdtst) == 0) { 10 | stop( 11 | "speedtest cli executable not found. ", 12 | "Use install_speedtest_cli() to install it.", 13 | call. = FALSE 14 | ) 15 | } 16 | 17 | progress <- if (progress[1]) "yes" else "no" 18 | progress <- sprintf("--progress=%s", progress) 19 | 20 | args <- c(progress, "--format=jsonl") 21 | 22 | system2( 23 | spdtst, 24 | args = args, 25 | TRUE 26 | ) -> res 27 | 28 | res <- lapply(res, jsonlite::fromJSON) 29 | 30 | download <- list() 31 | upload <- list() 32 | result <- list() 33 | 34 | for (.x in res) { 35 | 36 | if (.x$type == "download") { 37 | download <- append(download, list(.x)) 38 | } else if (.x$type == "upload") { 39 | upload <- append(upload, list(.x)) 40 | } else { 41 | result <- append(result, list(.x)) 42 | } 43 | 44 | } 45 | 46 | list( 47 | download = dplyr::bind_rows(lapply(download, dplyr::as_tibble)), 48 | upload = dplyr::bind_rows(lapply(upload, dplyr::as_tibble)), 49 | result = result 50 | ) -> res 51 | 52 | class(res) <- c("speedtest_cli_result") 53 | 54 | res 55 | 56 | } 57 | 58 | #' @rdname speedtest_cli 59 | #' @param x `speedtest_cli_result` object 60 | #' @param browse if `TRUE`, open a browser window with the results 61 | #' @param ... ignored 62 | #' @export 63 | print.speedtest_cli_result <- function(x, browse = FALSE, ...) { 64 | 65 | fmt <- scales::label_number_si(accuracy = 0.001, unit = "") 66 | 67 | cat( 68 | "Provider: ", x$result[[7]]$isp, "\n", 69 | " Ping: ", x$result[[7]]$ping$latency, " ms\n", 70 | "Download: ", fmt(x$result[[7]]$download$bytes), "\n", 71 | " Upload: ", fmt(x$result[[7]]$upload$bytes), "\n", 72 | " URL: ", x$result[[7]]$result$url, 73 | sep = "" 74 | ) 75 | 76 | if (browse) utils::browseURL(x$result[[7]]$result$url) 77 | 78 | } 79 | -------------------------------------------------------------------------------- /man/spd_download_test.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/download.r 3 | \name{spd_download_test} 4 | \alias{spd_download_test} 5 | \title{Perform a download speed/bandwidth test} 6 | \usage{ 7 | spd_download_test( 8 | server, 9 | config = NULL, 10 | summarise = TRUE, 11 | timeout = 60, 12 | .progress = "dplyr" 13 | ) 14 | } 15 | \arguments{ 16 | \item{server}{a data frame row from one of the functions that retrieves or 17 | filters a server list. You can pass in a full servers list but 18 | only the first entry will be processed.} 19 | 20 | \item{config}{client configuration retrieved via \code{\link[=spd_config]{spd_config()}}. If \code{NULL} it 21 | will be retrieved} 22 | 23 | \item{summarise}{the raw results from each test --- including file sizes --- 24 | will be returned if the value is \code{FALSE}. If \code{TRUE} only summary 25 | statistics will be returned.} 26 | 27 | \item{timeout}{max time (seconds) to wait for a connection or download to finish. 28 | Default is \code{60} seconds} 29 | 30 | \item{.progress}{if "\code{dplyr}" then \code{dplyr} progress bars will be used. If 31 | "\code{dot}" then "\code{.}" will be used. If anything else or "\code{none}", then 32 | no progress will be reported.} 33 | } 34 | \description{ 35 | Currently, ten tests are performed in increasing order of size. 36 | } 37 | \details{ 38 | This uses the legacy HTTP method of determining your bandwidth/speed and, 39 | as such, has many issues. Rather than hack-compensate for error-prone 40 | results with smaller files used on high-bandwidth connections, raw size + 41 | transfer speed data is returned enabling you to perform your own adjustments 42 | or choose which values to "believe". 43 | } 44 | \note{ 45 | speed/bandwidth values are in Mbits/s; these tests consume bandwidth so 46 | if you're on a metered connection, you may incur charges. 47 | } 48 | \examples{ 49 | \dontrun{ 50 | config <- spd_config() 51 | 52 | servers <- spd_servers(config=config) 53 | closest_servers <- spd_closest_servers(servers, config=config) 54 | only_the_best_severs <- spd_best_servers(closest_servers, config) 55 | 56 | spd_download_test(closest_servers, config=config) 57 | spd_download_test(best_servers, config=config) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /R/bestest.r: -------------------------------------------------------------------------------- 1 | #' Find "best" servers (latency-wise) from master server list 2 | #' 3 | #' The input `servers` data frame will be truncatred to the first `max` and 4 | #' HTTP and ICMP probe tests will be performed to determine initial retrieval 5 | #' speed and latency. Not all servers respond to ICMP requests due to the way 6 | #' their routers, switches or firewalls are configured. 7 | #' 8 | #' @md 9 | #' @param servers if not `NULL`, then the data frame from [spd_servers()]. If 10 | #' `NULL`, then [spd_servers()] will be called to retrieve the server list. 11 | #' @param config client configuration retrieved via [spd_config()]. If `NULL` it 12 | #' will be retrieved 13 | #' @param max the maximum numbers of "best" servers to return. This is hard-capped 14 | #' at 25 since Oookla is a free/sponsored service and if you plan on abusing 15 | #' it you'll have to write your own code to do so. Default is `10`. 16 | #' @return server list in order of latency closeness (retrieval speed column included) 17 | #' @note the list of target servers will be truncated to the first `max`. `max` may 18 | #' amount may not be returned if there were errors connecting to servers. 19 | #' @export 20 | spd_best_servers <- function(servers=NULL, config=NULL, max=10) { 21 | 22 | if (max > 25) max <- 25 23 | if (is.null(config)) config <- spd_config() 24 | if (is.null(servers)) servers <- spd_closest_servers(config=config) 25 | 26 | targets <- servers 27 | 28 | if (nrow(targets) > max) targets <- servers[1:max,] 29 | 30 | .lat_dat <- list() 31 | 32 | .COK <- function(res) { 33 | .lat_dat <<- c(.lat_dat, list(res)) 34 | } 35 | 36 | .CERR <- function(res) { cat("X")} 37 | 38 | targets$latency_url <- file.path(dirname(targets$url), "latency.txt") 39 | purrr::walk(targets$latency_url, curl::curl_fetch_multi, .COK, .CERR) 40 | 41 | curl::multi_run() 42 | 43 | purrr::map_df(.lat_dat, ~{ 44 | tibble( 45 | latency_url = .x$url, 46 | # TODO add some code to let this be a thing 47 | # ping_time = mean(pingr::ping(urltools::domain(.x$url)), na.rm=TRUE)/1000, 48 | total_time = .x$times["total"], 49 | retrieval_time = .x$times[6] - .x$times[5], 50 | test_result = rawToChar(.x$content) 51 | ) 52 | }) %>% 53 | dplyr::filter(!grepl("test=test", retrieval_time)) -> target_df 54 | 55 | dplyr::left_join(target_df, targets, "latency_url") %>% 56 | dplyr::arrange(total_time) %>% 57 | dplyr::select(-latency_url, -test_result) 58 | 59 | } 60 | 61 | -------------------------------------------------------------------------------- /R/upload.r: -------------------------------------------------------------------------------- 1 | #' Perform an upload speed/bandwidth test 2 | #' 3 | #' Currently, six tests are performed in increasing order of size. 4 | #' 5 | #' This uses the legacy HTTP method of determining your bandwidth/speed and, 6 | #' as such, has many issues. Rather than hack-compensate for error-prone 7 | #' results with smaller files used on high-bandwidth connections, raw size + 8 | #' transfer speed data is returned enabling you to perform your own adjustments 9 | #' or choose which values to "believe". 10 | #' 11 | #' @md 12 | #' @param server a data frame row from one of the functions that retrieves or 13 | #' filters a server list. You can pass in a full servers list but 14 | #' only the first entry will be processed. 15 | #' @param config client configuration retrieved via [spd_config()]. If `NULL` it 16 | #' will be retrieved 17 | #' @param summarise the raw results from each test --- including file sizes --- 18 | #' will be returned if the value is `FALSE`. If `TRUE` only summary 19 | #' statistics will be returned. 20 | #' @param timeout max time (seconds) to wait for a connection or download to finish. 21 | #' Default is `60` seconds 22 | #' @param .progress if "`dplyr`" then `dplyr` progress bars will be used. If 23 | #' "`dot`" then "`.`" will be used. If anything else or "`none`", then 24 | #' no progress will be reported. 25 | #' @note speed/bandwidth values are in Mbits/s; these tests consume bandwidth so 26 | #' if you're on a metered connection, you may incur charges. 27 | #' @export 28 | spd_upload_test <- function(server, config = NULL, summarise = TRUE, timeout=60, 29 | .progress = "dplyr") { 30 | 31 | if (nrow(server) > 1) server <- server[1,] 32 | 33 | if (is.null(config)) config <- spd_config() 34 | 35 | up_sizes <- c(131072, 262144, 524288, 1048576, 4194304, 8388608) 36 | 37 | pb <- dplyr::progress_estimated(length(up_sizes)) 38 | purrr::map(up_sizes, ~{ 39 | if (.progress == 'dplyr') pb$tick()$print() 40 | if (.progress == 'dots') cat(".", sep="") 41 | .dat <- sample(.base_raw, .x, replace=TRUE) 42 | res <- .upload_one(server$url[1], .dat, timeout) 43 | list(sz=.x, res=res$result) 44 | }) %>% 45 | purrr::discard(~is.null(.x$res)) %>% 46 | purrr::discard(~.x$res$status_code != 200) %>% 47 | purrr::map_df(~{ 48 | list( 49 | test = "upload", 50 | secs = .x$res$times[6] - .x$res$times[5], 51 | size = .x$sz 52 | ) 53 | }) %>% 54 | dplyr::mutate(bw = spd_compute_bandwidth(size, secs)) -> out 55 | 56 | if (.progress == 'dots') cat("\n", sep="") 57 | 58 | if (summarise) { 59 | dplyr::summarise( 60 | out, 61 | min = min(bw, na.rm = TRUE), 62 | mean = mean(bw, na.rm = TRUE), 63 | median = median(bw, na.rm = TRUE), 64 | max = max(bw, na.rm = TRUE), 65 | sd = sd(bw, na.rm = TRUE) 66 | ) -> out 67 | } 68 | 69 | out$id <- server$id 70 | 71 | dplyr::left_join(server, out, "id") 72 | 73 | } 74 | -------------------------------------------------------------------------------- /R/download.r: -------------------------------------------------------------------------------- 1 | #' Perform a download speed/bandwidth test 2 | #' 3 | #' Currently, ten tests are performed in increasing order of size. 4 | #' 5 | #' This uses the legacy HTTP method of determining your bandwidth/speed and, 6 | #' as such, has many issues. Rather than hack-compensate for error-prone 7 | #' results with smaller files used on high-bandwidth connections, raw size + 8 | #' transfer speed data is returned enabling you to perform your own adjustments 9 | #' or choose which values to "believe". 10 | #' 11 | #' @md 12 | #' @param server a data frame row from one of the functions that retrieves or 13 | #' filters a server list. You can pass in a full servers list but 14 | #' only the first entry will be processed. 15 | #' @param config client configuration retrieved via [spd_config()]. If `NULL` it 16 | #' will be retrieved 17 | #' @param summarise the raw results from each test --- including file sizes --- 18 | #' will be returned if the value is `FALSE`. If `TRUE` only summary 19 | #' statistics will be returned. 20 | #' @param timeout max time (seconds) to wait for a connection or download to finish. 21 | #' Default is `60` seconds 22 | #' @param .progress if "`dplyr`" then `dplyr` progress bars will be used. If 23 | #' "`dot`" then "`.`" will be used. If anything else or "`none`", then 24 | #' no progress will be reported. 25 | #' @note speed/bandwidth values are in Mbits/s; these tests consume bandwidth so 26 | #' if you're on a metered connection, you may incur charges. 27 | #' @export 28 | #' @examples \dontrun{ 29 | #' config <- spd_config() 30 | #' 31 | #' servers <- spd_servers(config=config) 32 | #' closest_servers <- spd_closest_servers(servers, config=config) 33 | #' only_the_best_severs <- spd_best_servers(closest_servers, config) 34 | #' 35 | #' spd_download_test(closest_servers, config=config) 36 | #' spd_download_test(best_servers, config=config) 37 | #' } 38 | spd_download_test <- function(server, config=NULL, summarise=TRUE, timeout=60, .progress="dplyr") { 39 | 40 | if (nrow(server) > 1) server <- server[1,] 41 | 42 | if (is.null(config)) config <- spd_config() 43 | 44 | down_sizes <- c(350, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000) 45 | 46 | dl_urls <- sprintf("%s/random%sx%s.jpg", dirname(server$url[1]), down_sizes, down_sizes) 47 | 48 | if (.progress == 'dplyr') pb <- dplyr::progress_estimated(length(dl_urls)) 49 | 50 | purrr::map(dl_urls, ~{ 51 | if (.progress == 'dplyr') pb$tick()$print() 52 | if (.progress == 'dots') cat(".", sep="") 53 | res <- .download_one(url=.x, timeout=timeout) 54 | res$result 55 | }) %>% 56 | purrr::discard(is.null) %>% 57 | purrr::discard(~.x$status_code != 200) %>% 58 | purrr::map_df(~{ 59 | list( 60 | test = "download", 61 | secs = .x$times[6] - .x$times[5], 62 | size = sum(purrr::map_dbl(names(unlist(.x$all_headers)), nchar)) + 63 | sum(purrr::map_dbl(unlist(.x$all_headers), nchar)) + length(.x$content) 64 | ) 65 | }) %>% 66 | dplyr::mutate(bw = spd_compute_bandwidth(size, secs)) -> out 67 | 68 | if (.progress == 'dots') cat("\n", sep="") 69 | 70 | if (summarise) { 71 | out <- dplyr::summarise(out, min=min(bw, na.rm=TRUE), mean=mean(bw, na.rm=TRUE), 72 | median=median(bw, na.rm=TRUE), max=max(bw, na.rm=TRUE), 73 | sd=sd(bw, na.rm=TRUE)) 74 | } 75 | 76 | out$id <- server$id 77 | 78 | dplyr::left_join(server, out, "id") 79 | 80 | } 81 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: rmarkdown::github_document 3 | editor_options: 4 | chunk_output_type: console 5 | --- 6 | ```{r pkg-knitr-opts, include=FALSE} 7 | hrbrpkghelpr::global_opts() 8 | ``` 9 | 10 | ```{r badges, results='asis', echo=FALSE, cache=FALSE} 11 | hrbrpkghelpr::stinking_badges() 12 | ``` 13 | 14 | # speedtest 15 | 16 | Tools to Test and Compare Internet Bandwidth Speeds 17 | 18 | ## Description 19 | 20 | The 'Ookla' 'Speedtest' site provides interactive and programmatic services to test and compare bandwidth speeds from a source node on the Internet to thousands of test servers. Tools are provided to obtain test server lists, identify target servers for testing and performing speed/bandwidth tests. 21 | 22 | ## What's Inside The Tin 23 | 24 | The following functions are implemented: 25 | 26 | ```{r ingredients, results='asis', echo=FALSE, cache=FALSE} 27 | hrbrpkghelpr::describe_ingredients() 28 | ``` 29 | 30 | ## Make a CLI utility 31 | 32 | While you can run `spd_test()` from an R console, it was desgined to be an easily wrapped into a `bash` (et al) alias or put into a small batch script. Or, you can just type out the following if you're fleet-of-finger/have dexterous digits: 33 | 34 | Rscript --quiet -e 'speedtest::spd_test()' 35 | 36 | which will look something like: 37 | 38 | ![](man/figures/spdtst.gif) 39 | 40 | ## TODO 41 | 42 | Folks interested in contributing can take a look at the TODOs and pick as many as you like! Ones with question marks are truly a "I dunno if we shld" kinda thing. Ones with exclamation marks are essentials. 43 | 44 | - [ ] Cache config in memory at startup vs pass around to functions? 45 | - [ ] Figure out how to use beta sockets hidden API vs the old Flash API? 46 | - [ ] Ensure the efficacy of relying on the cURL timings for speed measures for the Flash API 47 | - [ ] Figure out best way to capture the results for post-processing 48 | - [ ] Upload results to speedtest (tis only fair)! 49 | - [ ] Incorporate more network or host measures for better statistical determination of the best target! 50 | - [ ] `autoplot` support! 51 | - [ ] RStudio Add-in 52 | - [ ] Shiny app? 53 | 54 | ## Installation 55 | 56 | ```{r install-ex, results='asis', echo=FALSE, cache=FALSE} 57 | hrbrpkghelpr::install_block() 58 | ``` 59 | 60 | ## Usage 61 | 62 | ```{r libs, cache=FALSE} 63 | library(speedtest) 64 | library(stringi) 65 | library(hrbrthemes) 66 | library(ggbeeswarm) 67 | library(tidyverse) 68 | 69 | # current verison 70 | packageVersion("speedtest") 71 | ``` 72 | 73 | ### Download Speed 74 | 75 | ```{r dl-speeed, cache=TRUE} 76 | config <- spd_config() 77 | 78 | servers <- spd_servers(config=config) 79 | closest_servers <- spd_closest_servers(servers, config=config) 80 | only_the_best_severs <- spd_best_servers(closest_servers, config) 81 | ``` 82 | 83 | ### Individual download tests 84 | 85 | ```{r individ-dl, cache=TRUE} 86 | glimpse(spd_download_test(closest_servers[1,], config=config)) 87 | 88 | glimpse(spd_download_test(only_the_best_severs[1,], config=config)) 89 | ``` 90 | 91 | ### Individual upload tests 92 | 93 | ```{r individ-up, cache=TRUE} 94 | glimpse(spd_upload_test(only_the_best_severs[1,], config=config)) 95 | 96 | glimpse(spd_upload_test(closest_servers[1,], config=config)) 97 | ``` 98 | 99 | ### Moar download tests 100 | 101 | Choose closest, "best" and randomly (there can be, and are, some dups as a result for best/closest), run the test and chart the results. This will show just how disparate the results are from these core/crude tests. Most of the test servers compensate when they present the results. Newer, "socket"-based tests are more accurate but there are no free/hidden exposed APIs yet for most of them. 102 | 103 | ```{r moar-dl-tests, cache=TRUE} 104 | set.seed(8675309) 105 | 106 | bind_rows( 107 | 108 | closest_servers[1:3,] %>% 109 | mutate(type="closest"), 110 | 111 | only_the_best_severs[1:3,] %>% 112 | mutate(type="best"), 113 | 114 | filter(servers, !(id %in% c(closest_servers[1:3,]$id, only_the_best_severs[1:3,]$id))) %>% 115 | sample_n(3) %>% 116 | mutate(type="random") 117 | 118 | ) %>% 119 | group_by(type) %>% 120 | ungroup() -> to_compare 121 | 122 | select(to_compare, sponsor, name, country, host, type) 123 | 124 | map_df(1:nrow(to_compare), ~{ 125 | spd_download_test(to_compare[.x,], config=config, summarise=FALSE, timeout=30) 126 | }) -> dl_results_full 127 | 128 | mutate(dl_results_full, type=stri_trans_totitle(type)) %>% 129 | ggplot(aes(type, bw, fill=type)) + 130 | geom_quasirandom(aes(size=size, color=type), width=0.15, shape=21, stroke=0.25) + 131 | scale_y_continuous(expand=c(0,5)) + 132 | scale_size(range=c(2,6)) + 133 | scale_color_manual(values=c(Random="#b2b2b2", Best="#2b2b2b", Closest="#2b2b2b")) + 134 | scale_fill_ipsum() + 135 | labs(x=NULL, y=NULL, title="Download bandwidth test by selected server type", 136 | subtitle="Circle size scaled by size of file used in that speed test") + 137 | theme_ipsum_rc(grid="Y") + 138 | theme(legend.position="none") 139 | ``` 140 | 141 | ### Moar upload tests 142 | 143 | Choose closest and "best" and filter duplicates out since we're really trying to measure here vs show the disparity: 144 | 145 | ```{r moar-ul-tests, cache=TRUE} 146 | bind_rows( 147 | closest_servers[1:3,] %>% mutate(type="closest"), 148 | only_the_best_severs[1:3,] %>% mutate(type="best") 149 | ) %>% 150 | distinct(.keep_all=TRUE) -> to_compare 151 | 152 | select(to_compare, sponsor, name, country, host, type) 153 | 154 | map_df(1:nrow(to_compare), ~{ 155 | spd_upload_test(to_compare[.x,], config=config, summarise=FALSE, timeout=30) 156 | }) -> ul_results_full 157 | 158 | ggplot(ul_results_full, aes(x="Upload Test", y=bw)) + 159 | geom_quasirandom(aes(size=size, fill="col"), width=0.1, shape=21, stroke=0.25, color="#2b2b2b") + 160 | scale_y_continuous(expand=c(0,0.5)) + 161 | scale_size(range=c(2,6)) + 162 | scale_fill_ipsum() + 163 | labs(x=NULL, y=NULL, title="Upload bandwidth test by selected server type", 164 | subtitle="Circle size scaled by size of file used in that speed test") + 165 | theme_ipsum_rc(grid="Y") + 166 | theme(legend.position="none") 167 | ``` 168 | 169 | ## speedtest Metrics 170 | 171 | ```{r cloc, echo=FALSE} 172 | cloc::cloc_pkg_md() 173 | ``` 174 | 175 | ## Code of Conduct 176 | 177 | Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![Project Status: Active – The project has reached a stable, usable 3 | state and is being actively 4 | developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) 5 | [![Signed 6 | by](https://img.shields.io/badge/Keybase-Verified-brightgreen.svg)](https://keybase.io/hrbrmstr) 7 | ![Signed commit 8 | %](https://img.shields.io/badge/Signed_Commits-100%25-lightgrey.svg) 9 | [![Linux build 10 | Status](https://travis-ci.org/hrbrmstr/speedtest.svg?branch=master)](https://travis-ci.org/hrbrmstr/speedtest) 11 | [![Windows build 12 | status](https://ci.appveyor.com/api/projects/status/github/hrbrmstr/speedtest?svg=true)](https://ci.appveyor.com/project/hrbrmstr/speedtest) 13 | [![Coverage 14 | Status](https://codecov.io/gh/hrbrmstr/speedtest/branch/master/graph/badge.svg)](https://codecov.io/gh/hrbrmstr/speedtest) 15 | ![Minimal R 16 | Version](https://img.shields.io/badge/R%3E%3D-3.2.0-blue.svg) 17 | ![License](https://img.shields.io/badge/License-MIT-blue.svg) 18 | 19 | # speedtest 20 | 21 | Tools to Test and Compare Internet Bandwidth Speeds 22 | 23 | ## Description 24 | 25 | The ‘Ookla’ ‘Speedtest’ site provides 26 | interactive and programmatic services to test and compare bandwidth 27 | speeds from a source node on the Internet to thousands of test servers. 28 | Tools are provided to obtain test server lists, identify target servers 29 | for testing and performing speed/bandwidth tests. 30 | 31 | ## What’s Inside The Tin 32 | 33 | The following functions are implemented: 34 | 35 | - `install_speedtest_cli`: Provides instructions for installing the 36 | official speedtest CLI application 37 | - `nice_speed`: Convert a test speed, in Mbits/s, to its string 38 | representation along with appropriate units for the magnitude of the 39 | test speed 40 | - `spd_best_servers`: Find “best” servers (latency-wise) from master 41 | server list 42 | - `spd_closest_servers`: Find “closest” servers (geography-wise) from 43 | master server list 44 | - `spd_compute_bandwidth`: Compute bandwidth from bytes transferred 45 | and time taken 46 | - `spd_config`: Retrieve client configuration information for the 47 | speedtest 48 | - `spd_download_test`: Perform a download speed/bandwidth test 49 | - `spd_servers`: Retrieve a list of SpeedTest servers 50 | - `spd_test`: Test your internet speed/bandwidth 51 | - `spd_upload_test`: Perform an upload speed/bandwidth test 52 | - `speedtest_cli`: Perform an official Ookla Speed Test via their 53 | command line tools 54 | 55 | ## Make a CLI utility 56 | 57 | While you can run `spd_test()` from an R console, it was desgined to be 58 | an easily wrapped into a `bash` (et al) alias or put into a small batch 59 | script. Or, you can just type out the following if you’re 60 | fleet-of-finger/have dexterous digits: 61 | 62 | Rscript --quiet -e 'speedtest::spd_test()' 63 | 64 | which will look something like: 65 | 66 | ![](man/figures/spdtst.gif) 67 | 68 | ## TODO 69 | 70 | Folks interested in contributing can take a look at the TODOs and pick 71 | as many as you like\! Ones with question marks are truly a “I dunno if 72 | we shld” kinda thing. Ones with exclamation marks are essentials. 73 | 74 | - [ ] Cache config in memory at startup vs pass around to functions? 75 | - [ ] Figure out how to use beta sockets hidden API vs the old Flash 76 | API? 77 | - [ ] Ensure the efficacy of relying on the cURL timings for speed 78 | measures for the Flash API 79 | - [ ] Figure out best way to capture the results for post-processing 80 | - [ ] Upload results to speedtest (tis only fair)\! 81 | - [ ] Incorporate more network or host measures for better statistical 82 | determination of the best target\! 83 | - [ ] `autoplot` support\! 84 | - [ ] RStudio Add-in 85 | - [ ] Shiny app? 86 | 87 | ## Installation 88 | 89 | ``` r 90 | install.packages("speedtest", repos = c("https://cinc.rud.is", "https://cloud.r-project.org/")) 91 | # or 92 | remotes::install_git("https://git.rud.is/hrbrmstr/speedtest.git") 93 | # or 94 | remotes::install_git("https://git.sr.ht/~hrbrmstr/speedtest") 95 | # or 96 | remotes::install_gitlab("hrbrmstr/speedtest") 97 | # or 98 | remotes::install_bitbucket("hrbrmstr/speedtest") 99 | # or 100 | remotes::install_github("hrbrmstr/speedtest") 101 | ``` 102 | 103 | NOTE: To use the ‘remotes’ install options you will need to have the 104 | [{remotes} package](https://github.com/r-lib/remotes) installed. 105 | 106 | ## Usage 107 | 108 | ``` r 109 | library(speedtest) 110 | library(stringi) 111 | library(hrbrthemes) 112 | library(ggbeeswarm) 113 | library(tidyverse) 114 | 115 | # current verison 116 | packageVersion("speedtest") 117 | ## [1] '0.3.0' 118 | ``` 119 | 120 | ### Download Speed 121 | 122 | ``` r 123 | config <- spd_config() 124 | 125 | servers <- spd_servers(config=config) 126 | closest_servers <- spd_closest_servers(servers, config=config) 127 | only_the_best_severs <- spd_best_servers(closest_servers, config) 128 | ``` 129 | 130 | ### Individual download tests 131 | 132 | ``` r 133 | glimpse(spd_download_test(closest_servers[1,], config=config)) 134 | ## Observations: 1 135 | ## Variables: 15 136 | ## $ url "http://speedtest.peregrinenetworks.net:8080/speedtest/upload.php" 137 | ## $ lat 42.9956 138 | ## $ lng -71.4548 139 | ## $ name "Manchester, NH" 140 | ## $ country "United States" 141 | ## $ cc "US" 142 | ## $ sponsor "Peregrine Networks" 143 | ## $ id "30644" 144 | ## $ host "speedtest.peregrinenetworks.net:8080" 145 | ## $ url2 NA 146 | ## $ min 17.00748 147 | ## $ mean 63.20918 148 | ## $ median 66.31945 149 | ## $ max 81.70783 150 | ## $ sd 18.60229 151 | 152 | glimpse(spd_download_test(only_the_best_severs[1,], config=config)) 153 | ## Observations: 1 154 | ## Variables: 17 155 | ## $ total_time 0.082232 156 | ## $ retrieval_time 3.2e-05 157 | ## $ url "http://stosat-ndhm-01.sys.comcast.net:8080/speedtest/upload.php" 158 | ## $ lat 42.3578 159 | ## $ lng -71.0617 160 | ## $ name "Boston, MA" 161 | ## $ country "United States" 162 | ## $ cc "US" 163 | ## $ sponsor "Comcast" 164 | ## $ id "1774" 165 | ## $ host "stosat-ndhm-01.sys.comcast.net:8080" 166 | ## $ url2 "http://a-stosat-ndhm-01.sys.comcast.net/speedtest/upload.php" 167 | ## $ min 10.76603 168 | ## $ mean 38.85852 169 | ## $ median 39.13755 170 | ## $ max 70.70089 171 | ## $ sd 20.80209 172 | ``` 173 | 174 | ### Individual upload tests 175 | 176 | ``` r 177 | glimpse(spd_upload_test(only_the_best_severs[1,], config=config)) 178 | ## Observations: 1 179 | ## Variables: 17 180 | ## $ total_time 0.082232 181 | ## $ retrieval_time 3.2e-05 182 | ## $ url "http://stosat-ndhm-01.sys.comcast.net:8080/speedtest/upload.php" 183 | ## $ lat 42.3578 184 | ## $ lng -71.0617 185 | ## $ name "Boston, MA" 186 | ## $ country "United States" 187 | ## $ cc "US" 188 | ## $ sponsor "Comcast" 189 | ## $ id "1774" 190 | ## $ host "stosat-ndhm-01.sys.comcast.net:8080" 191 | ## $ url2 "http://a-stosat-ndhm-01.sys.comcast.net/speedtest/upload.php" 192 | ## $ min 8.765322 193 | ## $ mean 18.67036 194 | ## $ median 20.3484 195 | ## $ max 23.0133 196 | ## $ sd 5.342232 197 | 198 | glimpse(spd_upload_test(closest_servers[1,], config=config)) 199 | ## Observations: 1 200 | ## Variables: 15 201 | ## $ url "http://speedtest.peregrinenetworks.net:8080/speedtest/upload.php" 202 | ## $ lat 42.9956 203 | ## $ lng -71.4548 204 | ## $ name "Manchester, NH" 205 | ## $ country "United States" 206 | ## $ cc "US" 207 | ## $ sponsor "Peregrine Networks" 208 | ## $ id "30644" 209 | ## $ host "speedtest.peregrinenetworks.net:8080" 210 | ## $ url2 NA 211 | ## $ min 5.640102 212 | ## $ mean 18.29085 213 | ## $ median 20.99412 214 | ## $ max 21.7017 215 | ## $ sd 6.299546 216 | ``` 217 | 218 | ### Moar download tests 219 | 220 | Choose closest, “best” and randomly (there can be, and are, some dups as 221 | a result for best/closest), run the test and chart the results. This 222 | will show just how disparate the results are from these core/crude 223 | tests. Most of the test servers compensate when they present the 224 | results. Newer, “socket”-based tests are more accurate but there are no 225 | free/hidden exposed APIs yet for most of them. 226 | 227 | ``` r 228 | set.seed(8675309) 229 | 230 | bind_rows( 231 | 232 | closest_servers[1:3,] %>% 233 | mutate(type="closest"), 234 | 235 | only_the_best_severs[1:3,] %>% 236 | mutate(type="best"), 237 | 238 | filter(servers, !(id %in% c(closest_servers[1:3,]$id, only_the_best_severs[1:3,]$id))) %>% 239 | sample_n(3) %>% 240 | mutate(type="random") 241 | 242 | ) %>% 243 | group_by(type) %>% 244 | ungroup() -> to_compare 245 | 246 | select(to_compare, sponsor, name, country, host, type) 247 | ## # A tibble: 9 x 5 248 | ## sponsor name country host type 249 | ## 250 | ## 1 Peregrine Networks Manchester, NH United States speedtest.peregrinenetworks.net:8080 closest 251 | ## 2 Otelco Portland, ME United States oak-speedtest.otelco.com:8080 closest 252 | ## 3 netBlazr Somerville, MA United States speed0.xcelx.net:8080 closest 253 | ## 4 Comcast Boston, MA United States stosat-ndhm-01.sys.comcast.net:8080 best 254 | ## 5 netBlazr Somerville, MA United States speed0.xcelx.net:8080 best 255 | ## 6 Peregrine Networks Manchester, NH United States speedtest.peregrinenetworks.net:8080 best 256 | ## 7 Studenten Net Twente Enschede Netherlands ookla.snt.utwente.nl:8080 random 257 | ## 8 MIIT Kiev Ukraine speedtest.miit.ua:8080 random 258 | ## 9 Netcity Kielce Poland speedtest.netcity.pl:8080 random 259 | 260 | map_df(1:nrow(to_compare), ~{ 261 | spd_download_test(to_compare[.x,], config=config, summarise=FALSE, timeout=30) 262 | }) -> dl_results_full 263 | 264 | mutate(dl_results_full, type=stri_trans_totitle(type)) %>% 265 | ggplot(aes(type, bw, fill=type)) + 266 | geom_quasirandom(aes(size=size, color=type), width=0.15, shape=21, stroke=0.25) + 267 | scale_y_continuous(expand=c(0,5)) + 268 | scale_size(range=c(2,6)) + 269 | scale_color_manual(values=c(Random="#b2b2b2", Best="#2b2b2b", Closest="#2b2b2b")) + 270 | scale_fill_ipsum() + 271 | labs(x=NULL, y=NULL, title="Download bandwidth test by selected server type", 272 | subtitle="Circle size scaled by size of file used in that speed test") + 273 | theme_ipsum_rc(grid="Y") + 274 | theme(legend.position="none") 275 | ``` 276 | 277 | 278 | 279 | ### Moar upload tests 280 | 281 | Choose closest and “best” and filter duplicates out since we’re really 282 | trying to measure here vs show the disparity: 283 | 284 | ``` r 285 | bind_rows( 286 | closest_servers[1:3,] %>% mutate(type="closest"), 287 | only_the_best_severs[1:3,] %>% mutate(type="best") 288 | ) %>% 289 | distinct(.keep_all=TRUE) -> to_compare 290 | 291 | select(to_compare, sponsor, name, country, host, type) 292 | ## # A tibble: 6 x 5 293 | ## sponsor name country host type 294 | ## 295 | ## 1 Peregrine Networks Manchester, NH United States speedtest.peregrinenetworks.net:8080 closest 296 | ## 2 Otelco Portland, ME United States oak-speedtest.otelco.com:8080 closest 297 | ## 3 netBlazr Somerville, MA United States speed0.xcelx.net:8080 closest 298 | ## 4 Comcast Boston, MA United States stosat-ndhm-01.sys.comcast.net:8080 best 299 | ## 5 netBlazr Somerville, MA United States speed0.xcelx.net:8080 best 300 | ## 6 Peregrine Networks Manchester, NH United States speedtest.peregrinenetworks.net:8080 best 301 | 302 | map_df(1:nrow(to_compare), ~{ 303 | spd_upload_test(to_compare[.x,], config=config, summarise=FALSE, timeout=30) 304 | }) -> ul_results_full 305 | 306 | ggplot(ul_results_full, aes(x="Upload Test", y=bw)) + 307 | geom_quasirandom(aes(size=size, fill="col"), width=0.1, shape=21, stroke=0.25, color="#2b2b2b") + 308 | scale_y_continuous(expand=c(0,0.5)) + 309 | scale_size(range=c(2,6)) + 310 | scale_fill_ipsum() + 311 | labs(x=NULL, y=NULL, title="Upload bandwidth test by selected server type", 312 | subtitle="Circle size scaled by size of file used in that speed test") + 313 | theme_ipsum_rc(grid="Y") + 314 | theme(legend.position="none") 315 | ``` 316 | 317 | 318 | 319 | ## speedtest Metrics 320 | 321 | | Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) | 322 | | :--- | -------: | ---: | --: | ---: | ----------: | ---: | -------: | ---: | 323 | | R | 15 | 0.88 | 286 | 0.77 | 90 | 0.60 | 192 | 0.76 | 324 | | Rmd | 1 | 0.06 | 64 | 0.17 | 51 | 0.34 | 62 | 0.24 | 325 | | make | 1 | 0.06 | 20 | 0.05 | 9 | 0.06 | 0 | 0.00 | 326 | 327 | ## Code of Conduct 328 | 329 | Please note that this project is released with a Contributor Code of 330 | Conduct. By participating in this project you agree to abide by its 331 | terms. 332 | --------------------------------------------------------------------------------