REBOL Document

External IOS Server Applications

Document Version 1.1
IOS Version 1.0

Contents:

1. Overview
2. Server Side Applications
      2.1 Server Post Functions
      2.2 Launching Server Applications
3. The Example Application: Shipping
4. Creating the Scripts
5. The Scripts
      5.1 Install Ship - Server Post Function
      5.2 Ship - Client Script
      5.3 Ship-Job - Distribution Builder
      5.4 Form Letter

1. Overview

This document provides a working example of how to create, maintain, and execute a server-side application that runs externally to the IOS server.

The advantages of creating external server-side applications are:

  • They do not inhibit the operation of the IOS server when time consuming tasks are required.
  • Errors or crashes in external processes do not take down IOS.
  • IOS can launch and submit data to existing legacy and non-REBOL applications.
  • IOS can be used as an access "channel" for updating and accessing one or more of the external application's files and scripts, all within the secure and encrypted IOS remote connections.

2. Server Side Applications

2.1 Server Post Functions

Normally, IOS server scripts are created using fileset post functions. Post functions offer the advantage that they execute within the IOS server environment and can directly refer to the context of the fileset. As a result, post functions can easily access and manipulate their specific fileset elements such as tags, file lists, and user lists, keeping scripts small and easy to maintain.

However, long duration post functions should be avoided because they operate within the same process as the IOS server. If your IOS server-side application needs to access external resources such as databases, web sites, and email servers, you should consider launching a separate server-side application.

2.2 Launching Server Applications

The IOS server is built on REBOL/Command, giving it the ability to easily launch external server-side applications. Such applications run as separate processes and allow IOS to return to its distributed computing chores.

3. The Example Application: Shipping

The example provided here is an actual real-world application that is used by REBOL Technologies to create and ship its REBOL/Core, View, and Command products. This document focuses on the backend of the process which takes the order from the order database and ships it to a customer.

The diagram below outlines the process:

Here's how it works:

  1. A customer orders a product via a standard web page form.
  2. A CGI script (written in REBOL in our case) parses the form for errors and submits it to the order database.
  3. At REBOL Technologies the order is reviewed using a REBOL/Link client application. If the order looks ok, the application generates an encrypted license for the product which is sent to the IOS server via a post function.
  4. The post function launches a new process that embeds the license key within a distribution archive, compresses it, sends an email to the customer, and uploads the archive to the REBOL distribution site.
  5. The customer receives an email that contains a web link to the order and where to download it over the web.

This document focuses on steps 3 and 4, the IOS segments of the process.

4. Creating the Scripts

The IOS client not only runs the license creator, but manages the entire process. Scripts are created and edited on the IOS client and are then published back to the server where they are executed. FTP is not required.

All of this is done on an internal IOS installation at REBOL Technologies. (Which is why the desktop is skinned with a blue tint to make it stand out within the company.)

The "Ship" script is responsible for building the license and initiating process that builds the package that is shipped to the customer.

5. The Scripts

5.1 Install Ship - Server Post Function

The "Install-Ship" script contains the following code, and it is executed on the client to install the shipper fileset and its post function on the server.

This post function will be run within the server context. Its job is simple. It saves the order request as a synchronized file and launches REBOL/Command as a separate process.


    REBOL [
        Title: "Order Shipper (Server Post Function)"
        Type: 'link-app
        Version: 1.0.2
    ]

    if confirm "Reinstall shipping fileset?" [

    install-fileset [
        fileset: 'shipper

        tags: [
            access: [properties: rights: delete: change: ["Carl"] post: 'all]
        ]

        files: []

        post-locals: [err cmd]

        post-func: [
            if error? err: try [
                ; Save the request to a file (first item is the order#):
                add-file 'shipper join %projects/orders/requests/ message/1
                    compress mold message

                ; Build the REBOL command line:
                cmd: reform ["rebol-cmd -qws data/projects/orders/ship-job.r"
                    join %requests/ message/1 ">data/projects/orders/output"]

                ; Save it for the record: (optional)
                ;add-file 'shipper %projects/orders/input.txt compress cmd

                ; Process the request (save output on server):
                ; Note that the rebol-cmd key must be at server root location
                call cmd
            ][
                ; Let us know if a problem occurred:
                add-file 'shipper %projects/orders/error.txt
                    compress mold/only disarm :err
                return "error on server"
            ]
            true
        ]
    ]
    ]

When a post message occurs (from the client), the server quickly executes this script, launches REBOL/Command and returns to processing other requests.

Note that this installer script must be run from the client each time you modify the post function.

5.2 Ship - Client Script

The important part of the script that activates the above post function is shown below with example data.


    REBOL [
        Title: "Ship an Order"
        Type: 'link-app
    ]

    send-server post [
        shipper
        #1234 view "1201031"
        bob@example.net [#{12} #{34}]
    ]

    notify "Shipping initiated."

This script causes the previous post function to be called and passes it a REBOL block to use as input.

5.3 Ship-Job - Distribution Builder

The rest of the job is handled by a REBOL/Command script that is listed below. This script is executed outside the context of the IOS server, so if it takes some time to run or errors out, it will not affect IOS. (If you are not familiar with REBOL/Command, this script is a good example of what it can do.)

Note that to use REBOL/Command from IOS the license.key file must be located in the IOS server's root directory, otherwise the Command functions will not be unlocked.


    REBOL [
        Title: "Create and Ship a REBOL Package"
        Version: 1.2.1
        Needs: [command]
        Note: "This REBOL/Command script is launched from REBOL/IOS/Serve"
    ]

    ;-- If no argument to script, switch to debug mode:
    debug: none? system/script/args
    print [now system/script/args]

    ;-- Email setups
    set-net [orders@rebol.com mail.rebol.net]
    order-master: master@rebol.net

    ;-- Get order information:
    args: either debug [[#1 cmd "2002042" test@rebol.net [#{12} #{34}]]][
        load to-file system/script/args
    ]
    set [order prod exe customer key] args

    ;-- Log order received:
    log-file: join what-dir %log
    log: func [info] [write/append log-file reform info]
    log ["initiated:" prod mold order customer now newline]

    ;-- Get the form letter:
    letter: either not debug [load %letter.txt][
        ["Testing:" mold order newline "URL:" url newline]
    ]
    pass: decompress load %ftpuser.r

    ;-- Select archive type:
    type: any [select ["031" zip "011" lha] skip exe 4 'tar]

    ;-- Determine binary file suffix:
    suf: pick [".exe" ""] type = 'zip

    ;-- Generate a unique id for this job:
    random/seed now
    id: random "bcdfghjklmnpqrstvwxyz0123456789"
    clear skip id 6

    ;-- Main files and dirs:
    ftp: ftp://@ftp.reboltech.com/html/orders/
    site: http://www.reboltech.com/orders
    name: rejoin ["rebol" prod]
    new: to-file rejoin [name "/"] 
    src: to-file rejoin [prod "-dist/"]
    bin: to-file rejoin [prod "-bin/"]
    out: join %/tmp/rebol id
    outnew: out/:new

    ;-- Handy shell call function:
    shell: func [cmd] either debug [
        [call/wait probe reform cmd]
    ][
        [call/wait reform cmd]
    ]

    ;-- Cleanup and get starting files:
    if not exists? out [make-dir out]
    shell ["rm -rf" out/*]
    make-dir outnew
    shell ["cp -r" src/* outnew]

    ;-- Insert license key:
    save-license: func [
        "Save license file out in clean molded format"
        file [file!]
        license [block!]
        /local out
    ][
        out: copy "[^/"
        foreach val license [repend out [mold val newline]]
        append out "]^/"
        write file out
    ]
    save-license outnew/license.key key

    ;-- Verify program files exist:
    check-files: func [files [block! file!]][
        files: reduce files
        if file? files [files: reduce [files]]
        foreach file files [
            if not exists? file [
                send order-master reform [
                    reform ["Ship-Error:" prod mold order customer file newline]
                ]
                log ["file-error:" file prod mold order customer newline]
                quit
            ]
        ]
    ]

    ;-- Insert executable files:
    switch prod [
        cmd [
            bin1: rejoin [bin exe "c"]
            bin2: rejoin [bin exe "v"]
            check-files [bin1 bin2]
            shell ["cp" bin1 rejoin [outnew "rebol" suf]]
            shell ["cp" bin2 rejoin [outnew "rebolcv" suf]]
        ]
        view [
            bin1: join bin exe
            check-files bin1
            shell ["cp" bin1 rejoin [outnew "rebol" suf]]
        ]
        core [
            bin1: join bin exe
            check-files bin1
            shell ["cp" bin1 rejoin [outnew "rebol" suf]]
        ]
    ]

    ;-- Create archive:
    change-dir out
    result: switch type [
        tar [
            shell ["tar -cf rebol.tar" new]
            shell "gzip rebol.tar"
            ".tar.gz"
        ]
        zip [
            shell ["zip -r rebol.zip" new]
            ".zip"
        ]
        lha [
            shell ["lha a" rebol.lha new]
            ".lha"
        ]
    ]

    ;-- Upload to distribution site:
    archive: rejoin [%rebol- id result]
    data: read/binary join %rebol result
    insert find ftp "@" pass
    if not debug [write/binary ftp/:archive data]

    ;-- Notify customer via email:
    url: site/:archive
    letter: reform letter
    either debug [print [customer letter]][
        send customer letter
        send order-master head insert letter
            reform ["Shipped:" prod mold order customer newline]
    ]

    ;-- Cleanup:
    shell ["rm -rf" out]

    ;-- Log order completed:
    log ["shipped:" prod mold order customer id newline]

5.4 Form Letter

The form letter that is sent by the above script looks like this:


    {Your REBOL order} mold order {is ready.

    You can download your package from the URL listed here using
    a web browser or with REBOL itself:

    } url {

    In some browsers, you may need to right click on the link above.

    The downloaded file is an archive package that includes the
    program and other related files. To install, just unarchive
    (unzip) the package and run REBOL.

    Each time your REBOL program is started, a license key will be
    detected and the professional features will be unlocked. Note
    that the license.key file must be located in the same directory
    as the executable file or your current directory. If not, the
    features will not be enabled.

    Thanks again for purchasing REBOL.

    REBOL Technologies
    Sales and Support
    }

REBOL/MakeDoc 2.0

REBOL is a registered trademark of REBOL Technologies
Copyright 2004 REBOL Technologies

10-Sep-2004