Last active
          July 31, 2025 21:37 
        
      - 
      
 - 
        
Save shiftgeist/f6bf78c892e2981afc890ec74299d218 to your computer and use it in GitHub Desktop.  
    SwiftBar Latency/Ping
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | #!/usr/bin/env /opt/homebrew/bin/zx | |
| const HOSTS = [ | |
| 'cdn.search.brave.com', | |
| 'cloudflare.com', | |
| 'github.com', | |
| 'dns.google', | |
| 'time.google.com', | |
| 'logseq.com', | |
| 'de.pool.ntp.org', | |
| 'steampowered.com', | |
| 'mandelbaum.ai', | |
| ] | |
| const PING_COUNT = 10 | |
| const PING_INTERVAL = 0.2 | |
| const PING_MAX = 1000 | |
| const PING_CONSIDERED_HIGH = 150 | |
| const DISPLAY_MIN = 5 | |
| const HIST_MIN = 180 | |
| const HIST_PATH = '/tmp/ping_bars.json' | |
| const FONT_MONO = 'font=Monaco alternate=false' | |
| const COLOR_THRESHOLDS = [ | |
| [10, '#00FFFF'], | |
| [20, '#00E6BF'], | |
| [30, '#00CC80'], | |
| [40, '#00B340'], | |
| [50, '#009900'], | |
| [60, '#99D600'], | |
| [70, '#CCEB00'], | |
| [80, '#F1E033'], | |
| [90, '#FF9900'], | |
| [100, '#D84D00'], | |
| [125, '#B00000'], | |
| [150, '#CB0000'], | |
| [175, '#E50000'], | |
| [200, '#FF0000'], | |
| [250, '#D20631'], | |
| [300, '#A60D62'], | |
| [350, '#791393'], | |
| ] | |
| const LEVEL_OFFLINE = ['?', '#ff00f0', PING_MAX] | |
| const LEVEL_SET = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'] | |
| const INTERVAL = parseInt(path.basename(__filename).match(/\.(\d+).*\./)[1]) | |
| const DISPLAY_LEN = (DISPLAY_MIN * 60) / INTERVAL | |
| const HIST_LEN = (HIST_MIN * 60) / INTERVAL | |
| const ABORT_TIMEOUT = INTERVAL * 0.9 | |
| /** | |
| * @param {string} res | |
| * @returns {[avg: number, jitter: number]} | |
| */ | |
| const parsePing = res => { | |
| if (res.exitCode !== 0) return [PING_MAX, 0] | |
| const match = res.stdout.match(/min\/avg\/max\/stddev = [\d.]+\/([\d.]+)\/[\d.]+\/([\d.]+)/) | |
| if (!match) return [PING_MAX, 0] | |
| // TODO: add jitter match | |
| return Math.round(parseFloat(match[1])) | |
| } | |
| const linearGrowth = (start, end, count) => | |
| Array.from({ length: count }, (_, i) => Math.round(start + ((end - start) * i) / (count - 1))) | |
| const getLevel = (time, max) => { | |
| const set = LEVEL_SET | |
| const symbolThresholds = linearGrowth(1, max, set.length) | |
| const symbolIndex = symbolThresholds.findIndex(threshold => time < threshold) | |
| if (symbolIndex === -1) return LEVEL_OFFLINE | |
| const colorIndex = COLOR_THRESHOLDS.findIndex(([threshold]) => time <= threshold) | |
| if (colorIndex === -1) return LEVEL_OFFLINE | |
| return [set[symbolIndex], COLOR_THRESHOLDS[colorIndex][1], symbolThresholds[symbolIndex]] | |
| } | |
| const getHistory = async () => { | |
| try { | |
| return JSON.parse(await fs.readFile(HIST_PATH, 'utf8')).slice(-(HIST_LEN - 1)) | |
| } catch { | |
| return [] | |
| } | |
| } | |
| const saveHistory = h => fs.writeFile(HIST_PATH, JSON.stringify(h.length > HIST_LEN ? h.slice(-HIST_LEN) : h)) | |
| const getGraph = (h, high) => { | |
| const bars = h | |
| .map(v => getLevel(v, high)) | |
| .map(v => v[0]) | |
| .join('') | |
| if (h.length >= DISPLAY_MIN && bars.length !== h.length) return `??? "${bars}" (b ${bars.length}, h ${h})` | |
| return bars | |
| } | |
| const getAvg = arr => Math.round(arr.reduce((a, b) => a + b, 0) / arr.length) | |
| const getStats = (arr = []) => { | |
| const valid = arr.filter(t => t < PING_MAX) | |
| return { | |
| min: Math.round(Math.min(...valid)), | |
| avg: getAvg(valid), | |
| max: Math.round(Math.max(...valid)), | |
| timeout: arr.length - valid.length, | |
| } | |
| } | |
| const table = (data, params = '', header = true, fill = ' ', sep = ' ') => { | |
| const allParams = ` | trim=false ${FONT_MONO} ${params}` | |
| const widths = data[0].map((_, i) => Math.max(...data.map(r => String(r[i]).length))) | |
| return data | |
| .map(row => row.map((col, i) => String(col).padStart(widths[i], fill)).join(sep)) | |
| .join('\n') | |
| .replace(/$/gm, allParams) | |
| } | |
| try { | |
| const pingStart = Date.now() | |
| const PING_COMMANDS = HOSTS.map( | |
| site => `ping -i ${PING_INTERVAL} -c ${PING_COUNT} -t ${ABORT_TIMEOUT} -n -q '${site}'` | |
| ) | |
| // TODO: USE PING_COMMANDS | |
| const PING_PROMISES = HOSTS.map(site => | |
| $`ping -i ${PING_INTERVAL} -c ${PING_COUNT} -t ${ABORT_TIMEOUT} -n -q ${site}`.catch(e => e) | |
| ) | |
| const responses = await Promise.all(PING_PROMISES) | |
| const pingEnd = Date.now() | |
| const times = responses.map(parsePing) | |
| const stats = getStats(times) | |
| const data = await getHistory() | |
| data.push({ avg: stats.avg, time: Date.now() }) | |
| const hist = data.map(v => v.avg) | |
| saveHistory(data) | |
| const histStat = getStats(hist) | |
| const tri = hist.slice(-(DISPLAY_LEN * 4)) | |
| const triStat = getStats(tri) | |
| const display = hist.slice(-DISPLAY_LEN) | |
| const displayStat = getStats(display) | |
| const graph = getGraph(display, PING_CONSIDERED_HIGH) | |
| const [_, color] = getLevel(stats.avg, PING_MAX) | |
| console.log(`${graph} ⚡️${stats.avg}ms | color=${color} ${FONT_MONO}`) | |
| console.log('---') | |
| console.log( | |
| table([ | |
| [``, `L`, `M`, `H`, `?`], | |
| [`${INTERVAL}s`, stats.min, stats.avg, stats.max, `${stats.timeout}x`], | |
| [`${DISPLAY_MIN}m`, displayStat.min, displayStat.avg, displayStat.max, `${displayStat.timeout}x`], | |
| [`${Math.round((tri.length / 60) * INTERVAL)}m`, triStat.min, triStat.avg, triStat.max, `${triStat.timeout}x`], | |
| [`${HIST_MIN}m`, histStat.min, histStat.avg, histStat.max, `${histStat.timeout}x`], | |
| ]) | |
| ) | |
| console.log('---') | |
| HOSTS.forEach((site, i) => { | |
| // TODO: Show jitter | |
| console.log(`${site}: ${times[i]}ms`) | |
| console.log(`${PING_COMMANDS[i]} | alternate=true bash=/bin/sh param0="-c" param1='${PING_COMMANDS[i]}'`) | |
| }) | |
| console.log('---') | |
| const runtime = (pingEnd - pingStart) / 1000 | |
| const uptime = process.uptime() - runtime | |
| console.log(`Runtime: ${runtime.toFixed(3)}s / ${uptime.toFixed(3)}s`) | |
| console.log(`Refresh... | refresh=true`) | |
| } catch (error) { | |
| console.log(`Error (check details)`) | |
| console.log(error) | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment