sidorares / node-rfb2

rfb wire protocol client and server
MIT License
139 stars 27 forks source link

Add typescript bindings #15

Closed SerialVelocity closed 7 years ago

SerialVelocity commented 8 years ago

Hey,

Not sure if this is still maintained (works great for me!). Is it possible to add typescript bindings for this library? They need to be checked into https://github.com/DefinitelyTyped/DefinitelyTyped

Cheers, SerialVelocity

sidorares commented 8 years ago

Hi @SerialVelocity ! I don't have time to actively develop but trying to fix bugs if reported. Age you able to make pr with type annotations yourself?

SerialVelocity commented 8 years ago

I'll see what I can do. Is it ok if you update them if you ever change the types though? Should be super simple to do.

sidorares commented 8 years ago

If I merge your work I'll try to continue support it, though api is relatively stable and does not change that much

SerialVelocity commented 8 years ago

So nothing actually gets commited to your repository, the typings get added to this repository: https://github.com/DefinitelyTyped/DefinitelyTyped

sidorares commented 8 years ago

oh, I thought it should live alongside

SerialVelocity commented 8 years ago

Yeah, it's kinda hard to make them live alongside because of how projects pull in the bindings

SerialVelocity commented 8 years ago

In the end, I just implemented a few bindings for the types I used. Not enough to submit to DefinitelyTyped though. Here it is:

declare module "rfb2" {
    import * as events from "events";

    enum encodings {
        raw = 0,
        copyRect = 1,
        rre = 2,
        hextile = 5,
        zrle = 16,
        pseudoCursor = -239,
        pseudoDesktopSize = -223
    }

    enum security {
        None = 1,
        VNC = 2,
        ARD = 30
    }

    interface RfbClientArgs {
        host?: string,
        port?: number,
        password?: string,
        security?: Array<security>,
        credentialsCallback?(cli: RfbClient, callback: (password: string) => void): void,
        encodings?: Array<encodings>
    }

    interface Rectangle {
        encoding: encodings,
        x: number,
        y: number,
        height: number,
        width: number
        buffer: Buffer,
        data: Buffer
    }

    export class RfbClient extends events.EventEmitter {
        width: number;
        height: number;

        requestUpdate(incremental: boolean, x: number, y: number, width: number, height: number): void;
        end(): void;
    }

    export function createConnection(args: RfbClientArgs): RfbClient;
}
sidorares commented 8 years ago

thanks! I think I'll just add them alongside

vtolstov commented 7 years ago

any news?

sidorares commented 7 years ago

@vtolstov oh, completely forgot about this. Do you know where I put annotations? What's the standard naming conventions in TS world etc?

vtolstov commented 7 years ago

@sidorares i don't know =(. I have some projects that have ts inside js files, some of them have files with ts extension. Some of them have index.d.ts...

sidorares commented 7 years ago

@basarat maybe you can help us here?

basarat commented 7 years ago

I have some projects that have ts inside js files, some of them have files with ts extension. Some of them have index.d.ts...

TS is deisgned to match the project nature. For this project considering its package.json

  "main": "rfbclient.js",

I simply:

  "main": "rfbclient.js",
  "typings": "rfbclient",

And add rfbclient.d.ts. I'll send the PR soon :rose:

vtolstov commented 7 years ago

@sidorares please check provided pr, if it ok, i'm waiting for new package on npmjs.com to test it =)! If all ok i'm try to contribute to png encoding support because it very usable when displaying vnc to canvas.

sidorares commented 7 years ago

i'm try to contribute to png encoding support

looking forward to see, at the moment there is no working compression encoding in the client ( I started adding hextile but have not finished )

vtolstov commented 7 years ago

@sidorares thanks when the new package available on npmjs ?

sidorares commented 7 years ago

just pushed as v0.0.13

vtolstov commented 7 years ago

Thanks!

2017-01-10 2:05 GMT+03:00 Andrey Sidorov notifications@github.com:

just pushed as v0.0.13

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/sidorares/node-rfb2/issues/15#issuecomment-271436602, or mute the thread https://github.com/notifications/unsubscribe-auth/AAdYGy1PeIrWVV3_4TKoRTV80vj8B_eAks5rQr1MgaJpZM4HpnFW .

-- Vasiliy Tolstov, e-mail: v.tolstov@selfip.ru

sidorares commented 7 years ago

hi @vtolstov - any update on png encoding? Do you need help with this?

vtolstov commented 7 years ago

@sidorares yes i need some help... i found tight proto spec https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#tight-encoding and tight png spec http://wiki.qemu.org/Features/VNC_Tight_PNG

as i understand when i advertise tight png support via encoding -260, server send rectangle with type tight, but without compression len and raw png data. But i'm not fully understand how handle it in code.. https://github.com/sidorares/node-rfb2/compare/master...vtolstov:master?expand=1

sidorares commented 7 years ago

wow, thanks for the link to rfbproto repo, I was not aware of it - used this pdf previously - http://www.hep.phy.cam.ac.uk/vnc_docs/rfbproto.pdf

I'll have a look at tight encoding now

as i understand when i advertise tight png support via encoding -260, server send rectangle with type tight, but without compression len and raw png data.

yes ( as well as using other advertised encodings such as raw and copy rect, whatever server decides suits better for update )

sidorares commented 7 years ago

server send rectangle with type tight, but without compression len and raw png data.

First byte would indicate png as compression type, next 3 bytes - length of png buffer and following len bytes - png-encoded image

sidorares commented 7 years ago

RfbClient.prototype.readTight = function(rect, cb)
{
        var stream = this.pack_stream;
        var tight = {};
        var compControl = {};

        stream.get('C', function(compControl) {
    tight.compControl = compControl[0];
                // check  compControl is actually png, if so call readTightPng
        // ...
                readTightPng(rect, cb)
    });
}

RfbClient.prototype.readTightPng = function(rect, cb)
{
    var stream = this.pack_stream;
    var cli = this;

    stream.unpack('ccc', function(lenBytes) {
        // TODO: double check byte order
        var len = lenBytes[0] << 3 + lenBytes[1] << 2 + lenBytes[0]
        stream.unpack(len, function(pngData) {
           // not sure if we should decode png in this library. If so we could just emit it as raw rect
           // alternatively, let user of the library see sub encoding is 'png' and do something about png data
           rect.subEncoding = 'png'
           rect.pngData = pngData;
           cli.emit('rect', rect);
           cb(rect);
        })
    });

}```
sidorares commented 7 years ago

I guess adding jpeg would be trivial if we get png working

vtolstov commented 7 years ago

What do you think https://github.com/sidorares/node-rfb2/compare/master...vtolstov:master?expand=1

also i'm agree that we don't need to do anything with raw png data it can be easily placed in canvas via drawImage. Thats all.

sidorares commented 7 years ago

looks ok to me. Can you check byte order is correct and remove my comments?

Do you have local vnc server supporting tight/png to test against?

I'm testing with docker run -p 5902:5901 -p 6901:6901 consol/centos-xfce-vnc as server

actually it would be great to make this run on travis and perform some end to end tests

vtolstov commented 7 years ago

@sidorares i'm prefer to run qemu with small floppy image like freedos and vnc server binded to 127.0.0.1:5900

vtolstov commented 7 years ago

@sidorares how can i use example.js to get full framebuffer ?

sidorares commented 7 years ago

first update is always full screen (or alternatively you can set onlyChanged flag in requestUpdate )

vtolstov commented 7 years ago

@sidorares so on r.on('connect' i need to r.requestUpdate(false, 0, 0, r.width, r.height); ?

vtolstov commented 7 years ago
successfully connected and authorised
remote screen name: QEMU (xxx) width:1024 height: 768
enc: 0
enc: 0
vtolstov commented 7 years ago

So i recieve only raw =(

sidorares commented 7 years ago

is that builtin qemu server or you run something inside guest? It might just not have tight supported Try docker image I mentioned :)

sidorares commented 7 years ago

@sidorares so on r.on('connect' i need to r.requestUpdate(false, 0, 0, r.width, r.height); ?

right

vtolstov commented 7 years ago

what port i need to use to connect to docker container forwarded vnc port? also does consol/centos-xfce-vnc supports tight png ?

sidorares commented 7 years ago

5902 if started like docker run -p 5902:5901 -p 6901:6901 consol/centos-xfce-vnc

you can change it to any mapping (also I think there is http/websockets server as well on 6901 )

password is vncpassword - see https://github.com/ConSol/docker-headless-vnc-container

vtolstov commented 7 years ago

as i see this container send raw encoding frames =(

vtolstov commented 7 years ago

i think that my qemu misses tight png, so'i'm try to recompile it

vtolstov commented 7 years ago

I found the root case. Encoding needs to be specified in preferred order. For example if client supports raw and tightpng firstly you need to specify tightpng, and after raw. Now qemu sends tightpng encoding frames, but as i see i have decoding error in rfbclient.js

    <field name="vnc.server_message_type" showname="Server Message Type: Framebuffer Update (0)" size="1" pos="66" show="0" value="00">  
                    <field name="vnc.padding" showname="Padding" size="1" pos="67" show="" value=""/>                                                
                      <field name="vnc.fb_update_num_rects" showname="Number of rectangles: 7" size="2" pos="68" show="7" value="0007"/>         
                            <field name="" show="Rectangle #1" size="12" pos="70" value="0000000004000013fffffefc">              
                                                    <field name="vnc.fb_update_x_pos" showname="X position: 0" size="2" pos="70" show="0" value="0000"/>     
                                              <field name="vnc.fb_update_y_pos" showname="Y position: 0" size="2" pos="72" show="0" value="0000"/>                                  
                 <field name="vnc.fb_update_width" showname="Width: 1024" size="2" pos="74" show="1024" value="0400"/>                               
                   <field name="vnc.fb_update_height" showname="Height: 19" size="2" pos="76" show="19" value="0013"/>                                          
          <field name="vnc.fb_update_encoding_type" showname="Encoding type: Unknown (-260)" size="4" pos="78" show="-260" value="fffffefc"/>       
           </field>                                                                                                                              
                 <field name="" show="Rectangle #2" size="12" pos="82" value="800000000000001300e7000d">                                       
                           <field name="vnc.fb_update_x_pos" showname="X position: 32768" size="2" pos="82" show="32768" value="8000"/>
        <field name="vnc.fb_update_y_pos" showname="Y position: 0" size="2" pos="84" show="0" value="0000"/>
        <field name="vnc.fb_update_width" showname="Width: 0" size="2" pos="86" show="0" value="0000"/>
        <field name="vnc.fb_update_height" showname="Height: 19" size="2" pos="88" show="19" value="0013"/>
        <field name="vnc.fb_update_encoding_type" showname="Encoding type: Unknown (15138829)" size="4" pos="90" show="15138829" value="00e7000d"/>
      </field>
      </field>

as you see frame 2 invalid. i think that i have some error when decode first frame

vtolstov commented 7 years ago

May be we miss the len: length is compactly represented in one, two or three bytes, according to the following scheme:

vtolstov commented 7 years ago

@sidorares do you understand what they mean?

sidorares commented 7 years ago

yes, it's not exactly 3 bytes but 1 to 3 depending on content

here is java version implementing this logic: https://github.com/TurboVNC/tightvnc/blob/a235bae328c12fd1c3aed6f3f034a37a6ffbbd22/vnc_javasrc/RfbProto.java#L828 - need to implement something like there

vtolstov commented 7 years ago

i think the C or javascript are more easy: https://github.com/LibVNC/libvncserver/blob/master/libvncclient/tight.c#L596 https://github.com/novnc/noVNC/blob/master/core/rfb.js#L2269

vtolstov commented 7 years ago

@sidorares do you have some free time to help me with this ?=)

sidorares commented 7 years ago

maybe, doing some work in parallel as well :)

vtolstov commented 7 years ago
    function unpackLen() {
        stream.unpack('c', function(lenBytes) {
          return lenBytes[0]
        });
    }

    var len = unpackLen() & 0x7f
    if (len & 0x80) {
      len |= (unpackLen() & 0x7f) << 7
    }
    if (len & 0x80) {
      len |= (unpackLen() & 0xFF) << 14
    }
console.log('len: ' + len)
vtolstov commented 7 years ago

I'm try add this to readTightPng but len is 0 =(

sidorares commented 7 years ago

you have to move your code inside callback. unpackLen() does not return anything itself

  function unpackLen(cb) {
        stream.unpack('c', function(lenBytes) {
           var byte1 = lenBytes[0];
           if (byte1 & 0x80) {
               stream.unpack('c', function(lenBytes) {
                  var byte2 = lenBytes[0];
                  len = byte1 | ( byte2 & 0x7f) << 7;
                  // .... read byte3 if needed
               })
           } else {
               cb(byte1)
           }
    }
vtolstov commented 7 years ago

@sidorares and how can i use it ? sorry i'm newbie with nodejs =). Before that and now i'm writing on golang =)

sidorares commented 7 years ago

try to read some info from links below: http://callbackhell.com/ http://cwbuecheler.com/web/tutorials/2013/javascript-callbacks/ http://www.theprojectspot.com/tutorial-post/nodejs-for-beginners-callbacks/4 http://javascriptissexy.com/understand-javascript-callback-functions-and-use-them/ https://blog.risingstack.com/node-hero-async-programming-in-node-js/

and then I'll jump to help