code wiki / (root) / nx_torrent_reseed.nx

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}