I'm trying to wrap the peerjs libs in Smart Mobile Studio.
However I'm not sure what the rules for wrapping are.
I've looked at the RTL units and tried to deduce some rules from that.
However some questions still remain.
(function(exports){
var binaryFeatures = {};
binaryFeatures.useBlobBuilder = (function(){
...
})();
Peer.js starts with what looks like an anonymous function, with a single parameter (exports).
Is the following wrapper for binaryFeatures correct?
type
JBinaryFeatures = class external 'binaryFeatures'
public
function useBlobBuilder: boolean; external 'useBlobBuilder';
function useArrayBufferView: boolean; external 'useArrayBufferView';
end;
Next up is a function 'EventEmitter' which is used as a prototype for the connection classes (Peer/DataConnection etc).
How do I tell SMS that JPeer inherits from JEventEmitter?
I've tried:
JPeer = class{(TEventEmitter)} external 'Peer'
However this is not legal.
Finally some of the classes defined in Peer.js are never assigned to a variable, they are instead instantiated on the fly inside some class.
Do I use the external 'Object' construct for those classes, or do I name them according to the Peer.js file?
JNegotiator = class external 'Negotiator'
JNegotiator = class external 'Object'
Below are my attempt at writing a wrapper and the Peer.js file, that needs to be wrapped.
PeerWrapper.pas
unit PeerWrapper;
interface
{$R 'file:peer.js'}
uses
SmartCL.System;
type
JBinaryFeatures = class external 'binaryFeatures'
public
function useBlobBuilder: boolean; external 'useBlobBuilder';
function useArrayBufferView: boolean; external 'useArrayBufferView';
end;
// Parent class for the packing functions inside the connections.
// TBinaryPack = class external 'binaryPack'
// public
// function unpack(data: variant): variant; external 'unpack';
// function pack(data: variant): variant; external 'pack';
// end;
JReliable = class;
JUtil = class;
JPeer = class;
JDataConnection = class;
JMediaConnection = class;
//var
// FBlobBuilder: variant; external 'BlobBuilder';
// FBinaryFeatures: TBinaryFeatures; external 'binaryFeatures';
// //FBinaryPack: TBinaryPack;
// FReliable: TReliable; external 'reliable';
// FUtil: TUtil; external 'util';
// FPeer: TPeer; external 'Peer';
// FRTCSessionDescription: variant;
// FRTCPeerConnection: variant;
// FRTCIceCandidate: variant;
type
// Parent class for socket type connections.
JEventEmitter = class external 'eventEmitter'
public
constructor Create; external 'EventEmitter';
function addListener(&type, listener, scope, once: variant): TEventEmitter; external 'addListener';
function &on(&type, listener, scope, once: variant): TEventEmitter; external 'on';
function once(&type, listener, scope: variant): TEventEmitter; external 'once';
function removeListener(&type, listener, scope: variant): TEventEmitter; external 'removeListener';
function off(&type, listener, scope: variant): TEventEmitter; external 'off';
function removeAllListeners(&type: variant): TEventEmitter; external 'removeAllListeners';
function listeners(&type: variant): variant; external 'listeners';
function emit(&type: variant): boolean; external 'emit'; //vararg function
end;
JReliable = class external 'reliable'
public
constructor Create(dc, debug: variant); external 'Reliable';
procedure send(msg: variant); external 'send';
function higherBandwidthSDP(sdp: string): string; external 'higherBandwidthSDP';
function onmessage(msg: variant): variant; external 'onmessage';
end;
JUtil = class external 'util'
private
FCloud_host: string; external 'CLOUD_HOST';
FCloud_port: string; external 'CLOUD_PORT';
chunkedBrowsers: variant; external 'chunkedBrowsers';
chunkedMTU: integer; external 'chunkedMTU';
FLogLevel: integer; external 'logLevel';
FDefaultConfig: variant; external 'defaultConfig';
FDebug: boolean; external 'debug';
public
procedure setLogLevel(level: integer); external 'setLogLevel';
procedure setLogFunction(fn: variant); external 'setLogFunction';
function browser: string; external 'browser';
function supports: variant; external 'supports';
function validateId(id: string): boolean; external 'validateId';
function validateKey(key: string): boolean; external 'validateKey';
function unpack(data: variant): variant; external 'unpack';
function pack(data: variant): variant; external 'pack';
procedure log; external 'log';
procedure setZeroTimeout(global: variant); external 'setZeroTimeout';
function chunk(blob: variant): variant; external 'chunk';
procedure blobToArrayBuffer(blob: variant; callback: variant); external 'blobToArrayBuffer';
procedure blobToBinaryString(blob: variant; callback: variant); external 'blobToBinaryString';
function binaryStringToArrayBuffer(binary: variant): variant; external 'binaryStringToArrayBuffer';
function randomToken: string; external 'randomToken';
function isSecure: boolean; external 'isSecure';
property CloudHost: string read FCloud_host;
property CloudPort: string read FCloud_port;
property LogLevel: integer read FLogLevel;
property DefaultConfig: variant read FDefaultConfig;
property Debug: boolean read FDebug;
end;
JPeer = class{(TEventEmitter)} external 'Peer'
public
//inherited from EventEmitter
function addListener(&type, listener, scope, once: variant): TEventEmitter; external 'addListener';
function &on(&type, listener, scope, once: variant): TEventEmitter; external 'on';
function once(&type, listener, scope: variant): TEventEmitter; external 'once';
function removeListener(&type, listener, scope: variant): TEventEmitter; external 'removeListener';
function off(&type, listener, scope: variant): TEventEmitter; external 'off';
function removeAllListeners(&type: variant): TEventEmitter; external 'removeAllListeners';
function listeners(&type: variant): variant; external 'listeners';
function emit(&type: variant): boolean; external 'emit'; //vararg function
public
constructor Create(id: string; options: variant); external 'Peer';
function connect(peer: TPeer; options: variant): TDataConnection; external 'connect';
function call(peer: TPeer; stream: variant; options: variant): TMediaConnection; external 'call';
function getConnection(peer: TPeer; id: string): TEventEmitter; external 'getConnection';
procedure emitError(&type: variant; err: variant); external 'emitError';
procedure destroy; external 'destroy';
procedure disconnect; external 'disconnect';
procedure reconnect; external 'reconnect';
procedure listAllPeers(callback: variant); external 'listAllPeers';
end;
JDataConnection = class{(TEventEmitter)} external 'DataConnection'
public
//inherited from TEventEmitter
function addListener(&type, listener, scope, once: variant): TEventEmitter; external 'addListener';
function &on(&type, listener, scope, once: variant): TEventEmitter; external 'on';
function once(&type, listener, scope: variant): TEventEmitter; external 'once';
function removeListener(&type, listener, scope: variant): TEventEmitter; external 'removeListener';
function off(&type, listener, scope: variant): TEventEmitter; external 'off';
function removeAllListeners(&type: variant): TEventEmitter; external 'removeAllListeners';
function listeners(&type: variant): variant; external 'listeners';
function emit(&type: variant): boolean; external 'emit'; //vararg function
public
constructor Create(peer: TPeer; provider, options: variant); external 'Peer.connect.DataConnection';
procedure initialize(DataChannel: variant); external 'initialize';
procedure close; external 'close';
procedure send(data: variant; chunked: boolean); external 'send';
procedure handleMessage(message: variant); external 'handleMessage';
end;
JMediaConnection = class{(TEventEmitter)} external 'mediaConnection'
public
//inherited from EventEmitter
function addListener(&type, listener, scope, once: variant): TEventEmitter; external 'addListener';
function &on(&type, listener, scope, once: variant): TEventEmitter; external 'on';
function once(&type, listener, scope: variant): TEventEmitter; external 'once';
function removeListener(&type, listener, scope: variant): TEventEmitter; external 'removeListener';
function off(&type, listener, scope: variant): TEventEmitter; external 'off';
function removeAllListeners(&type: variant): TEventEmitter; external 'removeAllListeners';
function listeners(&type: variant): variant; external 'listeners';
function emit(&type: variant): boolean; external 'emit'; //vararg function
public
constructor Create(peer: TPeer; provider, options: variant); external 'Peer.call.MediaConnection';
procedure addStream(remoteStream: variant); external 'addStream';
procedure handleMessage(message: variant); external 'handleMessage';
procedure answer(stream: variant); external 'answer';
procedure close; external 'close';
end;
JNegotiator = class external 'Negotiator'
public
procedure startConnection(connection, options: variant); external 'startConnection';
procedure cleanup(connection: variant); external 'cleanup';
procedure handleSDP(&type, connection, sdp: variant); external 'handleSDP';
procedure handleCandidate(connection, ice: variant); external 'handleCandidate';
end;
JSocket = class{(TEventEmitter)} external 'Socket'
public
//inherited from EventEmitter
function addListener(&type, listener, scope, once: variant): TEventEmitter; external 'addListener';
function &on(&type, listener, scope, once: variant): TEventEmitter; external 'on';
function once(&type, listener, scope: variant): TEventEmitter; external 'once';
function removeListener(&type, listener, scope: variant): TEventEmitter; external 'removeListener';
function off(&type, listener, scope: variant): TEventEmitter; external 'off';
function removeAllListeners(&type: variant): TEventEmitter; external 'removeAllListeners';
function listeners(&type: variant): variant; external 'listeners';
function emit(&type: variant): boolean; external 'emit'; //vararg function
public
constructor Create(secure: boolean; host: string; port: integer; path, key: string); external 'Socket';
procedure start(id: string; token: string); external 'start';
procedure send(data: variant); external 'send';
procedure close; external 'close';
end;
implementation
end.
Link to peer.js on github
https://github.com/peers/peerjs/blob/master/lib/peer.js
How do I properly wrap the classes in this file?
The anonymous function in peerjs is used to create a private scope.
In Pascal terms, what is inside the anonymous function is like code inside an "implementation" section, and what is assigned to the "exports" is what will be exposed, sort of like an "interface" section.
So the binaryFeatures variable is not accessible to the outside (at least not from that snippet of code).
Rather than starting from the JS code, you should probably start from the documentation, and look at the code only to fill the holes/ambiguities in the documentation.
Also since JS does not have proper visibility management, "private" methods & fields are mimic'ed through a mix of obscurity and anonymous functions. For instance the methods prefixed with "_" in the peerjs source are intended as private/protected, so you should not expose them, even though they are accessible in JS.
So you can start from the Peer object, expose its methods, then expose the objects those methods use/need.
Other things to know:
So
and
are identical, but if you "Pascalized" the name, it becomes necessary:
as JS is case-sensitive