nx_intake_profile.nx source
↩ module page · 72 lines · 3167 B
1// nx_intake_profile.nx -- R6c: the LATEST-PROFILE loader, so the live dashboard + before-you-buy run on the
2// PERSON's submitted numbers, not the demo. When the intake handler records a profile (a content-addressed
3// survey record keyed by its CID), it ALSO writes a pointer "intake:latest:<respondent>" -> that CID (last-
4// wins). `ip_get` reads the pointer, loads the profile, and returns a field's value -- or a DEFAULT if the
5// person hasn't submitted yet (graceful fallback: real numbers when present, the worked example otherwise).
6// Reuses nx_survey (sv_load/sv_get/sv_atoi) + nx_seg_store. No floats, no hardware writes. license_tier: ORIGINAL
7import "nx_syscalls.nx"
8import "nx_seg_store.nx"
9import "nx_survey.nx"
10
11func ip_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
12
13// build the pointer key "intake:latest:<respondent>" into out (NUL-terminated); returns length.
14func ip_key(respondent: *u8, out: *u8) -> i64 {
15 var o: i64 = 0
16 let p: *u8 = "intake:latest:\x00" as *u8
17 var i: i64 = 0
18 while p[i] != (0 as u8) { out[o] = p[i]; o = o + 1; i = i + 1 }
19 i = 0
20 while respondent[i] != (0 as u8) { out[o] = respondent[i]; o = o + 1; i = i + 1 }
21 out[o] = 0 as u8
22 return o
23}
24
25// store the latest-profile pointer for a respondent (CID stored WITH its NUL so it reads back terminated).
26func ip_put_latest(prefix: *u8, respondent: *u8, cid: *u8) -> i64 {
27 let key: *u8 = sys_mmap(256)
28 ip_key(respondent, key)
29 let w: *i64 = ss_begin()
30 if ss_add(w, 1, key, cid, ip_len(cid) + 1) != 0 { return 0 - 1 }
31 if ss_commit(prefix, w, sys_now_us()) != 0 { return 0 - 2 }
32 return 0
33}
34
35// 1 if a profile exists for this respondent, else 0.
36func ip_exists(prefix: *u8, respondent: *u8) -> i64 {
37 let key: *u8 = sys_mmap(256)
38 ip_key(respondent, key)
39 let h: *i64 = ss_open(prefix)
40 if (h as i64) == 0 { return 0 }
41 let pp: *i64 = sys_mmap(16) as *i64
42 let ll: *i64 = sys_mmap(16) as *i64
43 if ss_hget(h, key, pp, ll) != 1 { return 0 }
44 return 1
45}
46
47// the latest profile's answer to `qid`, or `dflt` if no profile / field absent.
48func ip_get(prefix: *u8, respondent: *u8, qid: *u8, dflt: i64) -> i64 {
49 let key: *u8 = sys_mmap(256)
50 ip_key(respondent, key)
51 let h: *i64 = ss_open(prefix)
52 if (h as i64) == 0 { return dflt }
53 let pp: *i64 = sys_mmap(16) as *i64
54 let ll: *i64 = sys_mmap(16) as *i64
55 if ss_hget(h, key, pp, ll) != 1 { return dflt }
56 let cid: *u8 = pp[0] as *u8
57 let k: *i64 = sys_mmap(8 * 64) as *i64
58 let d: *i64 = sys_mmap(8 * 64) as *i64
59 let nf: i64 = sv_load(prefix, cid, k, d, 64)
60 if nf <= 0 { return dflt }
61 let v: *u8 = sv_get(k, d, nf, qid)
62 if (v as i64) == 0 { return dflt }
63 return sv_atoi(v)
64}
65
66// like ip_get, but treats a stored 0 as "unset" -> returns the default. For MONEY/RATE/PAYMENT fields where
67// 0 is meaningless (the handler stores absent number fields as 0). NOT for flags, where 0 is a real answer.
68func ip_get_pos(prefix: *u8, respondent: *u8, qid: *u8, dflt: i64) -> i64 {
69 let v: i64 = ip_get(prefix, respondent, qid, dflt)
70 if v <= 0 { return dflt }
71 return v
72}