UNPKG

git-read-pkt-line

Version:

read git packet lines (for smart protocol)

197 lines (163 loc) 3.58 kB
module.exports = readline var through = require('through') , binary = require('bops') , SIZE = binary.create(4) var _ = 0 , STATE_READY_CHANNEL = _++ , STATE_READY = _++ , STATE_RECV = _++ , STATE_MAYBE_PACK = _++ , STATE_PACK = _++ function readline(server_mode) { var stream = through(write) , caps = null , expect = 0 , size = 0 , accum = [] , got = 0 , seen = 0 , state = parse_size , done = false , type server_mode = !!server_mode var divine_capabilities = server_mode ? divine_server_capabilities : divine_client_capabilities return stream function write(buf) { accum[accum.length] = buf got += buf.length done = false while(!done) { state() } done = false } function parse_packfile() { stream.queue({ type: 'packfile' , data: take(got) , caps: null }) done = true } function parse_size() { type = 'pkt-line' if(got < 4) { done = true return } var bits = take(4) , human = binary.to(bits, 'utf8') if(human === 'PACK') { accum.unshift(bits) got += 4 state = parse_packfile return } size = parseInt(human, 16) if(!size) { return stream.queue({ type: 'pkt-flush' , data: null , caps: null }) } size -= 4 state = parse_first_byte } function parse_first_byte() { if(got < 1) { done = true return } state = parse_packet_line var peek = accum[0][0] type = peek === 1 ? 'packfile' : peek === 2 ? 'progress' : peek === 3 ? 'error' : 'pkt-line' } function parse_packet_line() { if(got < size) { done = true return } var buf = take(size) , check_caps_on = server_mode ? 2 : 1 ++seen if(!caps && seen === check_caps_on) { caps = divine_capabilities(buf) if(caps) { buf = binary.subarray(buf, 0, caps.idx + 1) buf[buf.length - 1] = 0x0A caps = caps.caps } } if(type !== 'pkt-line') { buf = binary.subarray(buf, 1) } stream.queue({ data: buf , type: type , caps: caps }) state = parse_size caps = null } function take(num) { var portion = [] , have = 0 if(num < 0) { throw new Error } while(have < num) { var sum = have + accum[0].length if(sum > num) { portion[portion.length] = binary.subarray(accum[0], 0, num - have) accum[0] = binary.subarray(accum[0], num - have) break } portion[portion.length] = accum.shift() have += portion[portion.length - 1].length } got -= num return binary.join(portion) } } function divine_client_capabilities(buf) { for(var i = 0, len = buf.length; i < len; ++i) { if(buf[i] === 0) { break } } if(i === len) { return null } return { idx: i , caps: binary.to(binary.subarray(buf, i+1, buf.length - 2), 'utf8').split(' ') } } function divine_server_capabilities(buf) { var is_fetch = binary.to(binary.subarray(buf, 0, 4)) === 'want' if(is_fetch) { for(var i = 45, len = buf.length; i < len; ++i) { if(buf[i] === 32) { break } } } else { for(var i = 0, len = buf.length; i < len; ++i) { if(buf[i] === 0) { break } } } if(i === len) { return null } return { idx: i , caps: binary.to(binary.subarray(buf, i+1, buf.length - 1), 'utf8').split(' ') } }