Add Garmin LiveTrack session tracking
CI / check (push) Successful in 6m49s
CI / deploy (push) Successful in 23s

A Gmail-watching Apps Script (documented in docs/deployment.adoc) posts
the session ID from each LiveTrack email to a new webhook, which stores
it in data/livetrack.json; a new sidebar panel lists what's been
received.
This commit is contained in:
randy committed 2026-09-06 21:05:35 +02:00
1 parent 60170efda2
commit f9ddf860ea
11 files changed
+279

No files matched your search

+63
View File
@@ -0,0 +1,63 @@
require "json"
require "fileutils"
module Maptool
# JSON-file-backed store of Garmin LiveTrack session IDs, appended to by a
# webhook whenever a new LiveTrack email arrives (see docs/deployment.adoc).
# Validity/expiry of a session isn't tracked here — checking whether a
# given ID still has live data is up to whoever polls Garmin with it.
class LiveTrackStore
def initialize(path)
@path = path
@mutex = Mutex.new
FileUtils.mkdir_p(File.dirname(@path))
File.write(@path, "[]") unless File.exist?(@path)
end
# Records `session_id`, moving it to the front if already present.
def add(session_id)
@mutex.synchronize do
sessions = read
sessions.reject! { |s| s["id"] == session_id }
sessions.unshift({ "id" => session_id, "received_at" => Time.now.utc.iso8601 })
File.write(@path, JSON.pretty_generate(sessions))
end
end
# Most recently received first.
def list
read
end
private
def read
JSON.parse(File.read(@path))
rescue Errno::ENOENT, JSON::ParserError
[]
end
end
end
if __FILE__ == $0
require "tmpdir"
Dir.mktmpdir do |dir|
store = Maptool::LiveTrackStore.new(File.join(dir, "livetrack.json"))
raise "expected empty list" unless store.list == []
store.add("abc123")
store.add("def456")
raise "expected 2 sessions" unless store.list.size == 2
raise "expected newest first" unless store.list.first["id"] == "def456"
store.add("abc123")
raise "expected re-added session moved to front, not duplicated" \
unless store.list.map { |s| s["id"] } == %w[abc123 def456]
reloaded = Maptool::LiveTrackStore.new(File.join(dir, "livetrack.json"))
raise "expected data to survive reload" unless reloaded.list.size == 2
end
puts "ok"
end