telescope.gno
4.76 Kb · 129 lines
1package telescope
2
3import (
4 "chain"
5 "strconv"
6
7 ns "gno.land/p/nym-vikbez000/nightsky0"
8 registry "gno.land/r/nym-vikbez000/nightsky0"
9)
10
11var telescope *ns.TelescopeRealm
12
13func init(cur realm) {
14 owner := "g13kytw9mpyutwmyg5eq7arqxqcszfl6uq4p89zg"
15
16 config := ns.NewTelescopeConfig(
17 "vik telescope", // name
18 "Seestar S30", // model
19
20 // Do not use too precise coordinates to keep some privacy
21 49.02, // latitude
22 1.15, // longitude
23 owner,
24 cur.PkgPath(),
25 )
26
27 telescope = ns.NewTelescopeRealm(&config)
28 telescope.Config.UpdateStatus("online")
29 registry.Register(cross(cur), config)
30}
31
32func Render(path string) string {
33 return telescope.RenderNightsky(path)
34}
35
36// Identity note: access control is keyed by the immediate caller via
37// cur.Previous().Address() — the statically-scoped realm handle, not the
38// stack-walking tx-origin. For a direct `gnokey maketx call` this resolves to
39// the signing EOA (matching the address-keyed access list); a call routed
40// through an intermediary realm is identified as that realm and denied unless
41// explicitly granted. This is the phishing-resistant pattern recommended in
42// gno-interrealm.md, and avoids the chain/runtime/unsafe primitives entirely.
43
44// SubmitCommand allows authorized users to submit telescope commands.
45// commandType: "capture" or "stop"
46// targetRA: Right Ascension in hours (0-24), leave empty for stop
47// targetDec: Declination in degrees (-90 to 90), leave empty for stop
48// exposure: Exposure time in seconds (1-300), leave empty for stop
49func SubmitCommand(cur realm, commandType, targetRA, targetDec, exposure string) {
50 caller := cur.Previous().Address().String()
51
52 var ra, dec float64
53 var exp int
54 if commandType == "capture" {
55 // Reject malformed numbers instead of silently treating them as 0,
56 // which would otherwise pass coordinate validation.
57 var err error
58 if ra, err = strconv.ParseFloat(targetRA, 64); err != nil {
59 panic("invalid RA: must be a number")
60 }
61 if dec, err = strconv.ParseFloat(targetDec, 64); err != nil {
62 panic("invalid Dec: must be a number")
63 }
64 if exp, err = strconv.Atoi(exposure); err != nil {
65 panic("invalid exposure: must be an integer")
66 }
67 }
68
69 telescope.SubmitCommand(caller, commandType, ra, dec, exp)
70 chain.Emit("CommandSubmitted", "type", commandType, "requester", caller)
71}
72
73// GrantAccess allows the owner to grant access to another user.
74// durationDays: 0 = never expires
75func GrantAccess(cur realm, address string, durationDays int) {
76 caller := cur.Previous().Address().String()
77 telescope.GrantAccess(caller, address, durationDays)
78 chain.Emit("AccessGranted", "address", address, "durationDays", strconv.Itoa(durationDays))
79}
80
81// RevokeAccess allows the owner to revoke access from a user.
82func RevokeAccess(cur realm, address string) {
83 caller := cur.Previous().Address().String()
84 telescope.RevokeAccess(caller, address)
85 chain.Emit("AccessRevoked", "address", address)
86}
87
88// GetNextCommand returns and removes the next command from the queue.
89// Called by the telescope controller.
90func GetNextCommand(cur realm) ns.TelescopeCommand {
91 caller := cur.Previous().Address().String()
92 return telescope.GetNextCommand(caller)
93}
94
95// UpdateStatus updates the telescope status locally and in the NightSky registry.
96// Valid values: "online", "offline", "busy", "error"
97func UpdateStatus(cur realm, status string) {
98 switch status {
99 case "online", "offline", "busy", "error":
100 default:
101 panic("invalid status: must be online, offline, busy, or error")
102 }
103 caller := cur.Previous().Address().String()
104 telescope.UpdateStatus(caller, status)
105 registry.UpdateTelescopeStatus(cross(cur), status)
106}
107
108// RecordCapture records a capture result locally and submits it to the NightSky network feed.
109func RecordCapture(cur realm, imageURL string, targetRA, targetDec float64, exposure int, capturedBy string) {
110 caller := cur.Previous().Address().String()
111 telescope.RecordCapture(caller, imageURL, targetRA, targetDec, exposure, capturedBy)
112 registry.SubmitCapture(cross(cur), imageURL, targetRA, targetDec, exposure, capturedBy)
113 chain.Emit("CaptureRecorded", "imageURL", imageURL, "capturedBy", capturedBy)
114}
115
116// ClearCommandQueue clears all pending commands (emergency stop).
117func ClearCommandQueue(cur realm) {
118 caller := cur.Previous().Address().String()
119 telescope.ClearCommandQueue(caller)
120 chain.Emit("CommandQueueCleared", "by", caller)
121}
122
123func GetCommandCount() int { return telescope.GetCommandCount() }
124func GetCaptureCount() int { return telescope.GetCaptureCount() }
125func GetAccessRuleCount() int { return telescope.GetAccessRuleCount() }
126func GetStatus() string { return telescope.Config.Status }
127func GetTelescopeName() string { return telescope.Config.Name }
128func GetTelescopeModel() string { return telescope.Config.Model }
129func GetOwner() string { return telescope.OwnerAddress }