nx_torrent_reseed.nx source
↩ module page · 102 lines · 7946 B
1// nx_torrent_reseed.nx -- register EVERY completed download in an area into the seeder registry so we SHARE
2// our whole library back (not just torrents that complete while a worker happens to be running). For each dir
3// in <area>/torrents.idx: if done>=npc (complete), info_hash = SHA1(download.meta) [the cached info-dict, so
4// its SHA1 IS the info_hash], plen from download.npc, total = download.part FILE SIZE, name = the dir name ->
5// idempotent append to the registry. Read-only except the append. Complements the worker's in-session
6// tg_autoseed (which only fires on live completion; autoresume skips already-complete downloads).
7// argv[1] = area outdir (e.g. /volume1/ai/torrent/media), argv[2] = seed registry path.
8// license_tier: ORIGINAL module: nishi-core.torrent.reseed depends: syscalls, sha1
9import "nx_syscalls.nx"
10import "nx_sha1.nx"
11const K_MAGIC_1024: i64 = 1024
12const K_MAGIC_65536: i64 = 65536
13const K_MAGIC_65535: i64 = 65535
14const K_MAGIC_1048576: i64 = 1048576
15const K_MAGIC_1048575: i64 = 1048575
16const K_MAGIC_1200: i64 = 1200
17const K_MAGIC_262144: i64 = 262144
18const K_MAGIC_2048: i64 = 2048
19
20func rs_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
21func rs_putn(v: i64) -> i64 { let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0; if m==0 {t[0]=48 as u8;k=1} while m>0 {t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} let o: *u8=sys_mmap(28); var i: i64=0; while i<k {o[i]=t[k-1-i];i=i+1} sys_write(1,o,k); return 0 }
22func rs_cat(dst: *u8, o: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){dst[o]=s[i];o=o+1;i=i+1} return o }
23func rs_itoa(v: i64, out: *u8) -> i64 { let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0; if m==0 {t[0]=48 as u8;k=1} while m>0 {t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k {out[i]=t[k-1-i];i=i+1} return k }
24func rs_read(path: *u8, buf: *u8, cap: i64) -> i64 {
25 let fd: i64=sys_openat_rd(path); if fd<0 { return 0-1 }
26 var off: i64=0; var go: i64=1
27 while go==1 { if off>=cap { go=0 } else { let r: i64=sys_read(fd,buf+off,cap-off); if r<=0 {go=0} else {off=off+r} } }
28 sys_close(fd); return off
29}
30func rs_has(hay: *u8, hlen: i64, ndl: *u8, nlen: i64) -> i64 {
31 var s: i64=0; while s+nlen<=hlen { var m: i64=1; var k: i64=0; while k<nlen { if hay[s+k]!=ndl[k] {m=0;k=nlen} else {k=k+1} } if m==1 { return 1 } s=s+1 }
32 return 0
33}
34
35func main(argc: i64, argv: *i64) -> i64 {
36 if argc < 3 { rs_puts("usage: nx_torrent_reseed <area-outdir> <seed_registry>\n" as *u8); sys_exit(2); return 2 }
37 let area: *u8 = argv[1] as *u8; let reg: *u8 = argv[2] as *u8
38 let hexd: *u8 = "0123456789abcdef" as *u8
39 let idxp: *u8 = sys_mmap(K_MAGIC_1024); var xo: i64=rs_cat(idxp,0,area); xo=rs_cat(idxp,xo,"/torrents.idx" as *u8); idxp[xo]=0 as u8
40 let idx: *u8 = sys_mmap(K_MAGIC_65536); let idxn: i64 = rs_read(idxp, idx, K_MAGIC_65535)
41 if idxn <= 0 { rs_puts("reseed: no torrents.idx in " as *u8); rs_puts(area); rs_puts("\n" as *u8); sys_exit(0); return 0 }
42 let regbuf: *u8 = sys_mmap(K_MAGIC_1048576); var regn: i64 = rs_read(reg, regbuf, K_MAGIC_1048575); if regn<0 { regn=0 }
43 var scanned: i64=0; var added: i64=0; var incomplete: i64=0
44 var ls: i64=0
45 while ls < idxn {
46 var le: i64=ls; var eol: i64=0
47 while eol==0 { if le>=idxn { eol=1 } else { if idx[le]==(10 as u8) { eol=1 } else { le=le+1 } } }
48 let blen: i64 = le-ls
49 if blen>0 { if blen<400 {
50 let b: *u8=sys_mmap(512); var c: i64=0; while c<blen { b[c]=idx[ls+c]; c=c+1 } b[blen]=0 as u8
51 let dir: *u8=sys_mmap(K_MAGIC_1024); var d: i64=rs_cat(dir,0,area); dir[d]=47 as u8; d=d+1; d=rs_cat(dir,d,b); dir[d]=0 as u8
52 // npc/plen
53 let npcp: *u8=sys_mmap(K_MAGIC_1200); var no: i64=rs_cat(npcp,0,dir); no=rs_cat(npcp,no,"/download.npc" as *u8); npcp[no]=0 as u8
54 let nb: *u8=sys_mmap(32); let nn: i64=rs_read(npcp,nb,16)
55 var npc: i64=0; var plen: i64=0
56 if nn>=4 { npc=((nb[0] as i64)<<24)|((nb[1] as i64)<<16)|((nb[2] as i64)<<8)|(nb[3] as i64) }
57 if nn>=8 { plen=((nb[4] as i64)<<24)|((nb[5] as i64)<<16)|((nb[6] as i64)<<8)|(nb[7] as i64) }
58 if npc>0 {
59 // done count
60 let donep: *u8=sys_mmap(K_MAGIC_1200); var od: i64=rs_cat(donep,0,dir); od=rs_cat(donep,od,"/download.done" as *u8); donep[od]=0 as u8
61 let dbuf: *u8=sys_mmap(K_MAGIC_262144); let dcnt: i64=rs_read(donep,dbuf,K_MAGIC_262144)
62 var done: i64=0; var q: i64=0; while q<dcnt { if (dbuf[q] as i64)==1 { done=done+1 } q=q+1 }
63 // complete = FULL (done>=npc) OR WANTED-complete (download.wanted present + every wanted piece done)
64 var complete: i64=0; if done>=npc { complete=1 }
65 if complete==0 { let wpp2: *u8=sys_mmap(K_MAGIC_1200); var ow: i64=rs_cat(wpp2,0,dir); ow=rs_cat(wpp2,ow,"/download.wanted" as *u8); wpp2[ow]=0 as u8
66 let wbuf: *u8=sys_mmap(K_MAGIC_262144); let wcnt: i64=rs_read(wpp2,wbuf,K_MAGIC_262144)
67 if wcnt>=npc { var allw: i64=1; var wq: i64=0; while wq<npc { if (wbuf[wq] as i64)==1 { if wq<dcnt { if (dbuf[wq] as i64)!=1 { allw=0; wq=npc } } else { allw=0; wq=npc } } wq=wq+1 } if allw==1 { complete=1 } } }
68 if complete==1 {
69 // meta -> info_hash = SHA1(meta)
70 let metap: *u8=sys_mmap(K_MAGIC_1200); var om: i64=rs_cat(metap,0,dir); om=rs_cat(metap,om,"/download.meta" as *u8); metap[om]=0 as u8
71 let meta: *u8=sys_mmap(K_MAGIC_262144); let msz: i64=rs_read(metap,meta,K_MAGIC_262144)
72 if msz>0 {
73 let ih: *u8=sys_mmap(24); sha1(meta,msz,ih)
74 let hx: *u8=sys_mmap(48); var hi: i64=0; while hi<20 { hx[hi*2]=hexd[((ih[hi] as i64)>>4)&15]; hx[hi*2+1]=hexd[(ih[hi] as i64)&15]; hi=hi+1 } hx[40]=0 as u8
75 // total = download.part size
76 let partp: *u8=sys_mmap(K_MAGIC_1200); var op: i64=rs_cat(partp,0,dir); op=rs_cat(partp,op,"/download.part" as *u8); partp[op]=0 as u8
77 let pf: i64=sys_openat_rd(partp); var total: i64=0; if pf>=0 { total=sys_lseek(pf,0,2); sys_close(pf) }
78 if total>0 {
79 if rs_has(regbuf,regn,hx,40)==1 { scanned=scanned+1 }
80 else {
81 let row: *u8=sys_mmap(K_MAGIC_2048); var ro: i64=0
82 ro=rs_cat(row,ro,b); row[ro]=9 as u8; ro=ro+1
83 var j: i64=0; while j<40 { row[ro]=hx[j]; ro=ro+1; j=j+1 } row[ro]=9 as u8; ro=ro+1
84 ro=ro+rs_itoa(plen,(row as i64+ro) as *u8); row[ro]=9 as u8; ro=ro+1
85 ro=ro+rs_itoa(total,(row as i64+ro) as *u8); row[ro]=9 as u8; ro=ro+1
86 ro=rs_cat(row,ro,partp); row[ro]=10 as u8; ro=ro+1
87 let wf: i64=__syscall(SYS_OPENAT, AT_FDCWD, reg as i64, 0x441, 0x1a4, 0, 0)
88 if wf>=0 { sys_write(wf,row,ro); sys_close(wf) }
89 var rc: i64=0; while rc<40 { regbuf[regn]=hx[rc]; regn=regn+1; rc=rc+1 } // dedup within this run
90 rs_puts(" + seeding " as *u8); rs_puts(b); rs_puts(" ih=" as *u8); rs_puts(hx); rs_puts("\n" as *u8)
91 added=added+1; scanned=scanned+1
92 }
93 }
94 }
95 } else { incomplete=incomplete+1 }
96 }
97 } }
98 ls=le+1
99 }
100 rs_puts("reseed area=" as *u8); rs_puts(area); rs_puts(" registered_new=" as *u8); rs_putn(added); rs_puts(" already/complete=" as *u8); rs_putn(scanned); rs_puts(" incomplete_skipped=" as *u8); rs_putn(incomplete); rs_puts("\n" as *u8)
101 sys_exit(0); return 0
102}