nx_steam_reviews.nx
buildroot/runtime/nx_steam_reviews.nx
about
nx_steam_reviews.nx -- STEAM REVIEW ADAPTER: the thin I/O program over nx_reviewmine_lib (/compare/reviewmine
R0 sr_fetch_pages, R1 rm_steam_ingest_page, R2 rm_stats, R3 rm_mine_rank). Every decision lives in the lib and
is gate-proven with planted pages; THIS file only fetches, banks, prints.
SOURCE: GET store.steampowered.com/appreviews/<appid>?json=1 (Steamworks doc "User Reviews - Get List"): filter
recent|updated|all, language, cursor (pass * first, then the returned cursor URL-ENCODED), num_per_page up to 100,
purchase_type all, review_type all; the default excludes off-topic review bombs (filter_offtopic_activity) and
this adapter keeps that default so the mined population matches the store's own score population.
WHAT IT BANKS (knowledge/reviews/steam/):
raw/<appid>/p<N>.json every page body exactly as received (provenance: the bytes we read)
<appid>.jrnl one row per review, append-only, dedupe by recommendationid (lib row grammar)
<appid>.seen the recommendationids already journaled (8-byte LE ints)
<appid>.summary appid|total_reviews|total_positive|total_negative|review_score|fetched_epoch|rows
PACING: every request goes through nx_paced_fetch (pf_before/pf_after) -- the ONE pacer the capture path shares
(mediaingest R0) -- plus a named inter-page delay from knowledge/reviewmine/steam_page_delay_ms.conf. A 429 is
fed to the pacer with its Retry-After and the page is retried ONCE after the pacer's wait; any other non-200
stops the run and says why. A truncated response is never ingested; it is announced and the run stops.
license_tier: ORIGINAL
dependencies 6 imports · 0 importers
imports: nx_syscalls.nxnx_x509_trust_store.nxnx_trust_store_load_from_certdata.nxnx_https_fetch_follow.nxnx_paced_fetch.nxnx_reviewmine_lib.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 28 | const SR_CERTDATA: *u8 = "data/mozilla_certdata.txt" |
| 29 | const SR_CERT_MAXCERTS: i64 = 512 |
| 30 | const SR_CERT_BUFCAP: i64 = 4194304 // 4 MiB scratch for the CA bundle parse (matches nx_source_health_probe) |
| 33 | const SR_RESP_CAP: i64 = 8388608 |
| 34 | const SR_REDIRECTS: i64 = 6 |
| 35 | const SR_PER_PAGE: i64 = 100 |
| 36 | const SR_HTTP_OK: i64 = 200 |
| 37 | const SR_HTTP_TOOMANY: i64 = 429 |
| 38 | const SR_BASE: *u8 = "knowledge/reviews/steam" |
| 39 | const SR_RAWDIR: *u8 = "knowledge/reviews/steam/raw" |
| 40 | const SR_STOPWORDS: *u8 = "knowledge/reviewmine/stopwords.conf" |
| 41 | const SR_DELAY_CONF: *u8 = "knowledge/reviewmine/steam_page_delay_ms.conf" |
| 42 | const SR_LEX_DEFECT: *u8 = "knowledge/reviewmine/lexicon_defect.conf" |
| 43 | const SR_LEX_FEATURE: *u8 = "knowledge/reviewmine/lexicon_feature.conf" |
| 44 | const SR_LEX_EXCEED: *u8 = "knowledge/reviewmine/lexicon_exceed.conf" |
| 45 | const SR_LEX_NOTMEET: *u8 = "knowledge/reviewmine/lexicon_notmeet.conf" |
| 46 | const SR_LEX_VALUE: *u8 = "knowledge/reviewmine/lexicon_value.conf" |
| 47 | const SR_LEX_DEMAND: *u8 = "knowledge/reviewmine/lexicon_demand.conf" |
| 51 | const SR_DEFAULT_DELAY_MS: i64 = 1500 |
| 52 | const SR_PATH_CAP: i64 = 512 |
| 53 | const SR_URL_CAP: i64 = 1024 |
| 54 | const SR_DEFAULT_TOP: i64 = 25 |
| 55 | const SR_DEFAULT_MIN_SUPPORT: i64 = 3 |
| 56 | const SR_STATUS_SLOT: i64 = 8 |
| 57 | const SR_CRLF_LEN: i64 = 2 // one CR LF |
| 58 | const SR_CRLF2_LEN: i64 = 4 // the blank line that ends an HTTP head |
| 59 | const SR_MAX_PAGE_ARG: i64 = 100000 // an upper bound on the max_pages argument itself, so a typo cannot loop forever |
| 60 | const SR_EXIT_USAGE: i64 = 2 // bad verb, bad appid, unreadable page file |
| 61 | const SR_EXIT_FAIL: i64 = 3 // the trust store could not be loaded |
| 62 | const SR_CURSOR_FIRST_PAGE: i64 = 42 // the byte * -- Steam's cursor for the first page (getreviews doc) |
| 63 | const SR_STOP_CAP: i64 = 64 // the stop-reason word |
| 64 | const SR_ARGC_MIN: i64 = 3 // <verb> <appid> |
| 65 | const SR_ARG_VERB: i64 = 1 // argv positions |
| 66 | const SR_ARG_APPID: i64 = 2 |
| 67 | const SR_ARG_FETCH_PAGES: i64 = 3 |
| 68 | const SR_ARG_FETCH_LANG: i64 = 4 |
| 69 | const SR_ARG_FETCH_FULL: i64 = 5 |
| 70 | const SR_ARG_INGEST_FILE: i64 = 3 |
| 71 | const SR_ARG_LANG: i64 = 3 // mine and rubric |
| 72 | const SR_ARG_TOP: i64 = 4 |
| 73 | const SR_ARG_MIN_SUPPORT: i64 = 5 |
| 75 | const SR_APPDETAILS_URL: *u8 = "https://store.steampowered.com/api/appdetails?filters=basic&appids=" |
| 76 | const SR_APPDETAILS_RAW: *u8 = "appdetails.json" |
functions
| 78 | func sr_stop(stop: *u8, s: *u8) -> i64 { let o: i64 = rm_cat(stop, 0, s); stop[o] = 0 as u8; return o } |
| 79 | func sr_body_start(buf: *u8, n: i64) -> i64 |
| 88 | func sr_retry_after(buf: *u8, n: i64, body: i64) -> i64 |
| 106 | func sr_conf_int(path: *u8, dflt: i64) -> i64 |
| 116 | func sr_path(out: *u8, appid: *u8, suffix: *u8) -> i64 |
| 124 | func sr_rawpath(out: *u8, appid: *u8, page: i64) -> i64 |
| 135 | func sr_url(out: *u8, appid: *u8, lang: *u8, cursor: *u8, clen: i64) -> i64 |
| 149 | func sr_usage() -> i64 |
| 159 | func sr_print_ingest(cnt: *i64) -> i64 |
| 166 | func sr_write_summary(appid: *u8, sum: *i64, rows: i64) -> i64 |
| 184 | func sr_name(appid: *u8) -> i64 |
| 242 | func sr_fetch(appid: *u8, max_pages: i64, lang: *u8, full: i64) -> i64 |
| 372 | func sr_ingest(appid: *u8, file: *u8) -> i64 |
| 395 | func sr_stats(appid: *u8) -> i64 |
| 437 | func sr_mine(appid: *u8, lang: *u8, top: i64, min_support: i64) -> i64 |
| 478 | func sr_lex(path: *u8, bit: i64, label: *u8) -> i64 |
| 485 | func sr_rubric(appid: *u8, lang: *u8, top: i64, min_support: i64) -> i64 |
| 588 | func main(argc: i64, argv: *i64) -> i64 |