Table of Contents
- Hop
- General configuration
- Server Information
- Server Configuration
- Responses
- hop.HTTPResponseHop( obj, [option] )
- hop.HTTPResponseXml( obj, [option] )
- hop.HTTPResponseString( string, [option] )
- hop.HTTPResponseJson( object )
- hop.HTTPResponseFile( path, [option] )
- hop.HTTPResponseAuthentication( msg, [request] )
- hop.HTTPResponseError( obj )
- hop.HTTPResponseAsync( sender, req )
- hop.HTTPResponseProxy( obj )
- Server
- new hop.Server( [ hostname [, port [, authorization [, ssl ] ] ] )
- Server.addEventListener( eventName, handler [, options] )
- Server.removeEventListener( eventName, handler )
- Broadcast
- EventMonitor
- hop.eventListenerMonitor( eventName )
- eventListenerMonitor.monitor( eventName )
- eventListenerMonitor.addEventListener( event, callback )
- Web Service
- hop.webService( url )
- WebServiceFrame.post([ success [, fail-or-options]] )
- WebServiceFrame.postSync([ success [, fail-or-option]] )
- Compiler Driver
- hop.compilerDriver
- hop.compilerDriver.policy
- hop.compilerDriver.pending
- hop.compilerDriver.addEventListener( eventName, handler [, options] )
- hop.compilerDrive.removeEventListener( eventName, handler )
- Miscellaneous
- hop.charsetConvert( text, source, target )
- hop.decodeHTML( string )
- hop.decodeURIComponent( string )
- hop.encodeHTML( string )
- hop.encodeURIComponent( string )
- hop.Cons()
- hop.List()
- hop.md5sum( string )
- hop.sha1sum( string )
- hop.compileXML( node [, ofile] [, backend] )
- Sub Modules
Hop
This module contains utilities for getting, controlling, and using the Hop server. The module defines functions to craft service responses, and a broadcast function that lets a server send events to registered remote clients.
The module also defines an API to invoke third party Web Services.
For ease of use, hop
is defined as a global object and can be used
directly without require.
General configuration
hop.isServer
The isServer
property is true for code executing on a server and false
for code executing on a client.
Server Information
The server properties defined below are read-only.
hop.port
The port number of the running Hop server. To set the port and protocol for the Hop server, see config.
console.log( "port:", hop.port );
hop.hostname
The host name of the running Hop server.
console.log( "hostname:", hop.hostname );
hop.version
The Hop version.
console.log( "Hop version:", hop.version );
Server Configuration
hop.httpAuthenticationMethod
The Hop HTTP authentication method. Can either be "basic"
or "digest"
.
console.log( "method:", hop.httpAuthenticationMethod );
hop.useProxy
Proxy to be used to access internet resources.
hop.useProxy = "192.168.3.4";
hop.enableProxying
Enable/disable Hop to act as an HTTP proxy.
hop.enableProxying = false;
Responses
Service result values are transformed into Hop responses before being sent to the clients.
hop.HTTPResponseHop( obj, [option] )
This class is used to respond values to client requests.
service getObj() {
return hop.HTTPResponseHop( { key: "foo", value: [ 1,2 3 ] } );
Note:
In normal situation, it is not necessary to explicitly build the
HTTPResponseHop
object as the runtime system automatically constructs
one when the response of a service is a compound JavaScript object.
The options list is:
startLine
: a string denoting the HTTP start line.contentType
: thecontent-type
of the response.charset
: the charset.header
: the full response header, an object.
hop.HTTPResponseXml( obj, [option] )
This class is used to deliver XML documents to client.
service getXml() {
return hop.HTTPResponseXml( <div>a div</div> );
The options list is:
backend
: the HTML backend (defaults to "HTML5")startLine
: a string denoting the HTTP start line.contentType
: thecontent-type
of the response.charset
: the charset.header
: the full response header, an object.
Note:
In normal situation, it is not necessary to explicitly build the
HTTPResponseXml
object as the runtime system automatically constructs
one when the response of a service is an XML fragment. It might be
useful to construct an HTTPResponseXML
explicitly when a header
is to be associated with the response. Example:
service foo() {
return hop.HTTPResponseXml(
<html>
<button onclick=~{console.log( document.cookie )}>show</button>
</html>,
{ contentType: "text/html", header: { "set-cookie": "a=b; HttpOnly" } } );
}
hop.HTTPResponseString( string, [option] )
This class is used to deliver plain character strings to client.
service getXml() {
return hop.HTTPResponseString(
"This resource does not exist here!",
{ startLine: "HTTP/1.0 404 File not found" } )
The options list is:
startLine
: a string denoting the HTTP start line.contentType
: thecontent-type
of the response.charset
: the charset.header
: the full response header, an object.
hop.HTTPResponseJson( object )
This convenience function returns an [application/json]
value from a
JavaScript object. It is the same as:
hop.HTTPResponseString( JSON.stringify( obj ), { contentType: 'application/json' } )
startLine
: a string denoting the HTTP start line.contentType
: thecontent-type
of the response.charset
: the charset.header
: the full response header, an object.
hop.HTTPResponseFile( path, [option] )
This class is used to respond files to clients. The argument path
is
the full path of a existing file. The option is an object whose fields can
be:
contentType
: thecontent-type
of the response.charset
: the charset.header
: the full response header, an object.
Example
This example shows the most efficient way to deliver content file
to client. Using a HTTPResponseFile
object deliver much better
performance than reading the file content first and then seding a
buffer or a string the client.
In this example, the file replied to the client is to be interpreted
as a plain text file alhgouth it is a JavaScript program. To tell
the Web browser not to interpret the file, the mime type text/plain
is specified in the response option.
The charset encoding of the file is also provided using the charset
attribute.
file/file.js
service file() {
var pre = <pre/>;
return <html>
~{
var entityMap = {
"&": "&",
"<": "<",
">": ">",
'"': '"',
"'": ''',
"/": '/'
};
function escapeHTML( string ) {
return String( string ).replace(
/[&<>"'\/]/g,
function ( s ) {
return entityMap[s];
} );
}
}
<button onclick=~{
var file = ${fileGet.resource( "file.js" )};
${fileGet}( file )
.post( function( txt ) {
${pre}.innerHTML = escapeHTML( txt )
} );
}>
click me
</button>
${pre}
</html>;
}
service fileGet( path ) {
return hop.HTTPResponseFile( path,
{ contentType: "text/plain",
charset: hop.locale } );
}
console.log( "Go to \"http://%s:%d/hop/file\"", hop.hostname, hop.port );
Note:
HTTPResponseFile is a much faster way to send a file to a client, althought,
the same behaviour can also be implemented combining standard fs
operations
and HTTPResponseString
values.
hop.HTTPResponseAuthentication( msg, [request] )
This class is used to respond HTTP 401 Unauthorized
response to Web
client.
Note:
the class hop.HTTPResponseAuthentication
is a convenience class.
The same behavior can be implemented using hop.HTTPResponseString
and passing a startLine
value in the optional argument.
Example
This example shows how to use HTTPResponseAuthentication
to request
Web browser authentication.
The example counts the number of request (the variable count
). Each request
decrements the counter but only passes through when it reaches 0
.
authentication/authentication.js
var count = 2;
service authenticationAccept() {
switch( count-- ) {
case 2:
return hop.HTTPResponseAuthentication( "I don't know you", this );
case 1:
return hop.HTTPResponseAuthentication( "Do you really insist?", this );
case 0:
count = 2;
return "Ok for this time";
}
}
service authentication() {
var console = <div/>;
return <html>
<div>
Click 3 times the "click me" button.
Permission granted on the third request.
</div>
<button onclick=~{
${authenticationAccept}()
.post( function( v ) { ${console}.innerHTML = v },
{ fail: function( v ) { ; } } ) }>
click me
</button>
${console}
</html>
}
console.log( "Go to \"http://%s:%d/hop/authentication\"", hop.hostname, hop.port );
hop.HTTPResponseError( obj )
Respond an error value to the client, which either invokes the fail
callback of the post
service call, or raises an exception.
hop.HTTPResponseAsync( sender, req )
Asynchronous responses are used when a service cannot returns instantly
a value to a client because it relies on an asynchronous computation.
In that situation, the service must produce a hop.HTTPResponseAsync
which
is interpreted by the builtin server as a delayed reply.
- The argument
sender
is a function of one argument. This function is automatically invoked by the runtime system with a value that is a function of one parameter. Invoking that function provokes the delivery of the reply to the client. - The argument
req
is either a request object (thethis
value of the service invokation) or an object containing the optional fields.currentRequest
: the request object.contentType
: thecontent-type
of the response.charset
: the charset.header
: the full response header, an object.
Example
This example illustraed service declaration with fixed number of argument and asynchronous responses.
The service foo
must call the service bar
on the same host.
Calling the serving synchronously would result in a dead lock
as only one thread is in charge of handling services.
The call to bar
must then be asynchronous. This is acheived
by applying the post
method of the frame computed with
bar( x + 1 )
.
The service foo
relies on a asynchronous computation. It then cannot
respond immediately to the client. It will be in position to
reply only when the invocation of bar
has completed. This is
implemented using a hop.HTTPResponseAsync
object. The argument
sendReponse
is a function automatically created by the runtime
system. When invoked with sendReponse( e )
the result of the
service bar
is replied to the cilent which has called foo
.
svc3/svc3.js
service svc3() {
return <html>
<button onclick=~{
${foo}( 1 )
.post( function( r ) {
document.body.appendChild( r );
} )
}>click</button>
</html>;
}
service foo( x ) {
console.log( "in foo x=", x );
return hop.HTTPResponseAsync(
function( sendResponse ) {
bar( x + 1 ).post( function( e ) {
sendResponse( e );
} )
}, this );
}
service bar( x ) {
console.log( "in bar x=", x );
return <div>${ x + 1 }</div>;
}
console.log( "Go to \"http://%s:%d/hop/svc3\"", hop.hostname, hop.port );
Note:
the class hop.HTTPResponseAsync
is the base class for
implementing asynchronous reponses. Returning
Promise
objects as a similar behavior and is encouraged. The service foo
defined above can be implemented as:
service foo( x ) {
console.log( "in foo x=", x );
return new Promise( function( resolve, reject ) {
bar( x + 1 ).post( resolve );
}
}
Invoking the resolve
function actually sends the responds to the client.
Invoking the reject
as the same effect of responding a HHTPResponseError
value.
hop.HTTPResponseProxy( obj )
The hop.HTTPResponseProxy
objects are to be used when a remote resource
can be access othwerwise. For instance, these situations arise because of
the security enforcement of the Web browsers. Some resources have to be
downloaded from the origin server. Using a hop.HTTPResponseProxy
object
enables the web page to only use local URLs, that are proxied to the actual
remote resources by the server.
Example
This example illustrates standard client image manipulations and use
of hop.HTTPResponseProxy
objects.
Security enforcement of Web browsers prevent manipulation image pixels whose origin differs from the origin of the main page. To workaround this problem, the manipulated image is proxied by the Hop server. The Web browser only sees relative local URLs.
image/image.js
var img_default = "http://t1.gstatic.com/images?q=tbn:ANd9GcRUADxj_7NEl8RAFNM-s6x3Wgp1QIg81QHRMVeOuMHBklr1JWddmQ";
var colors_default = [
{red: 252, green: 27, blue: 0},
{red: 125, green: 167, blue: 129},
{red: 255, green: 122, blue: 10}
];
service imgProxy( url ) {
return hop.HTTPResponseProxy( url );
}
service image( o ) {
var url = o && "url" in o ? o.url : img_default;
return <html>
~{
function drawImage( url, colors ) {
var img = new Image();
var src = document.getElementById( "src" );
var dst = document.getElementById( "dst" );
var ctxsrc = src.getContext( "2d" );
var ctxdst = dst.getContext( "2d" );
img.onload = function( e ) {
src.width = img.width;
src.height = img.height;
dst.width = img.width;
dst.height = img.height;
ctxsrc.drawImage( img, 0, 0 );
var f = ctxsrc.getImageData( 0, 0, img.width, img.height );
ctxdst.putImageData( colorize( f, colors ), 0, 0 );
}
img.src = url;
}
function colorize( frame, colorset ) {
var data = frame.data;
var l = data.length / 4;
for( var i = 0; i < l; i++ ) {
var r = data[ i*4 ];
var g = data[ i*4 + 1 ];
var b = data[ i*4 + 2 ];
var range = Math.floor( (0.65*r + 0.22*g + 0.13*b) / 86 );
var cs = colorset[ range ];
data[ i*4 ] = 0.7*cs.red + 0.3*r;
data[ i*4 + 1 ] = 0.7*cs.green + 0.3*g;
data[ i*4 + 2 ] = 0.7*cs.blue + 0.3*b;
}
return frame;
}
window.addEventListener( "load", function( e ) {
drawImage( ${imgProxy( url )}, ${colors_default} )
} )
}
<img src=${url}/>
<canvas id="src" style="display: none"/>
<canvas id="dst"/>
</html>
}
console.log( "Go to \"http://%s:%d/hop/image\"", hop.hostname, hop.port );
Server
Server objects denotes a remote server. They are used to attached listeners to server events (see Broadcast) and to invoke services from server to another server (see service).
new hop.Server( [ hostname [, port [, authorization [, ssl ] ] ] )
Creates a new server object. The arguments are as follows:
hostname
: a string, the name or IP number of the remote host that will emit signals. If omitted, defaults to the running host name.port
: the port number of the remote host. If omitted, defaults to the running Hop port.authorization
: a string, an optional authorization for accessing the remote host. This has the syntax of the framepost
method.ssl
: a optional boolean. When true, the established channel between the two servers uses SSL.
Server.addEventListener( eventName, handler [, options] )
Use this method on the client side to register to the eventName
server event. The effect of this method is to establish a persistent
connection with the Hop server, register the client for the given
event type, and trigger the handler whenever the event is received by
the client. handler
takes one argument, the event. The transmitted
value
can be retrieved in the value
property of the event.
When used within a web browser, connection is established with the Hop
server serving the current page, the exact syntax is
server.addEventListener( eventName, handler )
where server
denotes
the current server (the runtime system automatically binds the
server
variable to the current server).
server.addEventListener( 'refreshScore', function( event ) {
var score = event.value;
var scoreElement = this.document.getElementById( 'score' );
// update GUI element with new score
Two predefined events are automatically sent to clients:
ready
: that event is emitted when a new listener is attached to a server.down
: that event is emtted when the connection with the server is lost.
Server.removeEventListener( eventName, handler )
Removes an attached listener.
Broadcast
Broadcast is an abstraction on top of webSockets to let a Hop server send events to connected clients (either web browsers or Hop client processes). Connections originate from the client to the server, so broadcast can be used even in the asymetric web topology where clients most often lie behind a NAT router or firewall and would not accept a connection from a remote server (forbidding the remote server to invoke services running on the client process).
hop.broadcast( eventName, value )
Generates an event of type eventName
with payload value
. The event
is broadcast over the network to all registered clients. eventName
is cast into a String, value
can be any serializable object,
including JavaScript objects, Hop.js services, and
xml-elements. Clients register to specific broadcast events with the
addEventListener
method.
hop.broadcast( 'refreshScore', 14 );
hop.signal()
This function is similar to broadcast
but only one receiver will be
notified of the message.
EventMonitor
Event listener monitors are used to react to client connection requests.
hop.eventListenerMonitor( eventName )
Creates a new event monitor on event eventName
.
eventListenerMonitor.monitor( eventName )
Add a new event to be monitored by this monitor.
eventListenerMonitor.addEventListener( event, callback )
The argument event
can be newListener
or removeListener
:
newListener
: the associated callback will be invoked each time a client will register a listener on eventeventName
, the event name used to build the monitor.removeListener
: the associated callback will be invoked on client deconnection.
Example:
const monitor = new hop.eventListenerMonitor( "foo" );
monitor.monitor( "bar" );
console.log( "monitor=", monitor );
var o = { x: 1, y: 2 };
monitor.addEventListener( "newListener", e => {
console.log( "newL=", e.data, e.target.header.host );
setTimeout( _ => hop.broadcast( e.data, { x: 1, y: 2 } ), 2000 );
if( e.data == "foo" ) {
setTimeout( _ => {
console.log( "bcast gee" );
hop.broadcast( "gee", "dummy" )
}, 3000 );
}
} );
monitor.addEventListener( "removeListener", e => console.log( "remL=", e.data, e.target.header.host ) );
Web Service
A WebService reifies an API, i.e., a set of services, that let you invoke third party WebServices the same way you invoke Hop services (see Interoperable WebServices for interoperability notes).
var hop = require( 'hop' );
var mymemory = hop.webService( "http://mymemory.translated.net/api/get" );
mymemory( {q: 'My tailor is rich.', langpair: 'en|fr' } ).post( function( result ) {
console.log( result.responseData );
}, { fail: function( error ) {
console.log( 'failure' );
} });
hop.webService( url )
Use this method to declare a remote WebService,that can later be
invoked with named arguments. url
is the url of the WebService.
Call the returned function with an object argument containing the
named arguments you want to send to the WebService. The returned value
is a WebServiceFrame (very similar in use to Service Frames).
WebServiceFrame.post([ success [, fail-or-options]] )
Invokes asynchronously the webService. The optional success
argument,
when provided, must be a function of one argument, which is set the
the value returned by the WebService.
if the optional argument fail-or-options
is a procedure, it is
invoked if an error occurs during the WebService invocation. If
fail-or-options
is an object, it contains optional parameters to the
WebService invocation.
The list of valid options are:
hostname
: the remote host.port
: the remote host port.authorization
: a identification of the formname:password
.fail
: a failure callback.scheme
: the scheme used for the request (defaults tohttp
).ssl
: a boolean to enable secure connections.timeout
: a number of milliseconds.method
: the method of the call (e.g.,GET
orPOST
).header
: the complete header of the request. The header is an regular object.body
: a string, denoting the body of the request.
Example:
var ws = hop.webService( "http://localhost:1337/api/oauth/token" );
ws()
.postSync(
{ method: "POST",
header: { "content-type": "application/x-www-form-urlencoded" },
body: "grant_type=password&client_id=android&client_secret=SomeRandomCharsAndNumbers&username=myapi&password=abc1234" } );
WebServiceFrame.postSync([ success [, fail-or-option]] )
The synchronous version of post
. Returns the value returned by the
service. Since postSync
blocks the execution of the client process
until the service returns a value, it is strongly advised to use
the asynchronous post
when applicable. The options are shared with the
post
method.
Compiler Driver
The compiler driver provides information about the background compilation status.
hop.compilerDriver
hop.compilerDriver.policy
The compilation policy. The possible values are:
none
: never compile.aot
: compile before loading.nte
: compile for the next execution. The pending compilation are stopped when the current execution is about to end.nte+
: compile for the next execution and wait for all running compilations before ending current execution.
hop.compilerDriver.pending
The number of pending background compilations.
hop.compilerDriver.addEventListener( eventName, handler [, options] )
This method is used to add an listener to the compiler driver. The known events are
start
: emitted when a background compilation starts. Theevent.target
denotes the file name.end
: emitted when a background compilation ends. Theevent.target
denotes the file name andevent.value
the compilation termination status (an integer).all
: emitted when all background compilation complete. This event fires, when the listener is added and when there is no pending compilation.
hop.compilerDrive.removeEventListener( eventName, handler )
Removes an attached listener.
Miscellaneous
hop.charsetConvert( text, source, target )
Converts the text
string from charset source
into charset target
.
url/url.js
"use hopscript";
var mymemory = hop.webService( "http://mymemory.translated.net/api/get" );
function translateText( text, lang = "en|fr" ) {
var o = mymemory( { q: text, langpair: lang } ).postSync();
if( o.responseStatus === 200 ) {
var t = o.responseData.translatedText;
return hop.charsetConvert( unescape( t ), "UTF-8" );
}
}
service url() {
var output = <div/>;
var input = <input value="toto n'est pas content"/>;
var select = <select>
<option label="fr->en" value="fr|en">fr->en</option>
<option label="en->fr" value="en|fr">en->fr</option>
</select>
var translate = service( text, langpair ) {
return translateText( text, langpair );
};
return <html>
<div>
${select}
${input}
<button onclick=~{
${translate}( ${input}.value, ${select}.value )
.post( function( v ) { ${output}.innerHTML = v; } )}>
translate
</button>
${output}
</div>
</html>;
}
console.log( "Go to \"http://%s:%d/hop/url\"", hop.hostname, hop.port );
hop.decodeHTML( string )
Decodes an encoded HTML string.
hop.decodeHTML( 'jean <dupont>' );
// "jean <dupont>"
hop.decodeURIComponent( string )
Decodes an encoded URI component.
hop.encodeURIComponent( 'jean dupont' );
// "jean%20dupont"
hop.encodeHTML( string )
Encodes an HTML string into a textual string.
hop.encodeHTML( 'jean <dupont>' );
// "jean <upont>"
hop.encodeURIComponent( string )
Encodes a string into a valid URI component.
hop.encodeURIComponent( 'jean dupont' );
// "jean%20dupont"
hop.Cons()
This function is a constructor to create native (Bigloo) objects.
hop.List()
This function is a constructor to create native (Bigloo) objects.
hop.md5sum( string )
Computes the md5sum of a string.
hop.md5sum( 'jean dupont' );
// "b38bed581de7b86dd6fc8355c73cebf2"
hop.sha1sum( string )
Computes the sha1 sum of a string.
hop.sha1sum( 'jean dupont' );
// "7461340811509ec24dd1c1a32504a01e24423768"
hop.compileXML( node [, ofile] [, backend] )
Compile a XML node
into HTML. If no output file is specified,
the product of the compilation is returned in a buffer. The
optional backend
argument is a string denoting the HTML version to be
used for the compilation.
var node = <html><div onclick=~{alert( "clicked" )}>click me</div></html>
console.log( hop.compileXML( node, false, "html5" ) );
Note:
explicit compilation to HTML using hop.compileXML
is unncessary
for service responses. Services can directly return XML objects
in response to HTTP requests.
Sub Modules
The following properties lead to sub modules that can be loaded using
the require
function.
var hop = require( 'hop' );
var config = require( hop.config );
hop.config
See config.
hop.fontifier
hop.markdown
See markdown.
hop.notepad
hop.security
hop.spage
See spage.
hop.tree
See tree.
hop.user
See user.