At the time we developed the Meso language, IMOP was an application layer protocol running on top of TCP that has its own message format. However, since 2012, we have made substantial change to the protocol and use HTTP as its transport instead. In this new version of IMOP, an IMOP request is just a regular HTTP request. This allows us to make IMOP calls from a web browser.

The information bellow is about the new HTTP-based IMOP protocol. Although it is different from the protocol used in the current Meso language implementation, they are both based on the same fundamental concept that use reflection to introspect the definition of an unknown object over the network. We may update the Meso language implementation to adopt this new protocol version in the future.

The Internet Metaobject Protocol (IMOP)

IMOP is a very simple protocol that utilizes HTTP for distributed OO programming. The following is a Javascript snippet that operates a remote object through IMOP:

var obj = imop.bind('imop://foo.com/an/object/ref');
if (obj.instanceOf('imop://bar.com/an/abstract/interface')) {
    obj.call('func1', [ arg1, arg2 ], callback);
}

An IMOP object is an remote object that can be operated through IMOP RPC calls. The object's location is identified by an IMOP URL like imop://foo.com/an/object/ref above. Each object supports a set of IMOP interface types, and each interface type declares a set of methods that the object must implement. An IMOP interface type is also identified by an IMOP URL like imop://bar.com/an/abstract/interface above.

Reflection

To identify whether an IMOP URL points to an object or an interface type, and what interfaces an object supports or what methods an interface type declares or so, one may use an IMOP reflection call to query the URL's location. An IMOP reflection call is just a HTTP GET request send to the location where imop:// in the URL is treated as http://. The remote resource will return a type descriptor written in JSON.

The followings are some reflection request/response examples. See reflection response message format to understand what's inside the JSON descriptor.

Example 1:

Reflect on URL imop://hongzhenchao.com:9988/agent. The descriptor shows that it is an object implementing the imop://metop.co/api/sys/Agent interface.

GET /agent HTTP/1.1
Host: hongzhenchao.com:9988
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
    "imop": "0.1",
    "desc": {
        "kind": "object",
        "implements": [
            "imop://metop.co/api/sys/Agent"
        ]
    }
}
Example 2

Reflect on URL imop://metop.co/api/sys/Agent. The descriptor shows that it is an interface type that extends from another interface imop://metop.co/api/sys/Entity, and defines an additional method named getLoginURL.

GET /api/sys/Agent HTTP/1.1
Host: metop.co
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
    "imop": "0.1",
    "desc": {
        "kind": "interface",
        "extends": [
            "imop://metop.co/api/sys/Entity"
        ],
        "methods": [{
            "name": "getLoginURL",
            "out":  "imop:string"
        }]
    }
}
Example 3

Reflect on URL imop://metop.co/api/fs/FileInfo. It is a struct type that defines some fields in addition to those defined in its parent struct type imop://metop.co/api/sys/EntityInfo.

GET /api/fs/FileInfo HTTP/1.1
Host: metop.co
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
    "imop": "0.1",
    "desc": {
        "kind": "struct",
        "extends": "imop://metop.co/api/sys/EntityInfo",
        "fields": [
           { "name": "size",  "type": "imop:int"    },
           { "name": "atime", "type": "imop:int"    },
           { "name": "mtime", "type": "imop:int"    },
           { "name": "ctime", "type": "imop:int"    },
           { "name": "path",  "type": "imop:string" },
           { "name": "href",  "type": "imop:string" }
        ]
    }
}
Method Invocation

An IMOP RPC request is a JSON message sent via an HTTP POST request. The response message is also written in JSON. Here are some examples:

Example 1:

This example invokes the method func1 with three primitive argument values "hello", 123, and true on the imop://foo.com/my/object object. The object returns a primitive value "world".

POST /my/object HTTP/1.1
Host: foo.com
Content-Type: application/json;charset=UTF-8

{
    "imop": "0.1",
    "meta": "CALL",
    "method": "func1",
    "args": [ "hello", 123, true ]
}
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
    "imop": "0.1",
    "code": "2000",
    "msg": "OK",
    "ret": "world"
}
Example 2:

This example invokes the method list with no arguments on the imop://foo.com/my/object object. The object returns an array of objects that implement the imop://metop.co/api/fs/File interface type.

POST /my/object HTTP/1.1
Host: foo.com
Content-Type: application/json;charset=UTF-8

{
    "imop": "0.1",
    "meta": "CALL",
    "method": "list",
    "args": []
}
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
    "imop": "0.1",
    "code": "2000",
    "msg": "OK",
    "ret": {
        "type": "imop://metop.co/api/fs/File[]",
        "value": [
            "imop://abc.com/fs/file1", "imop://abc.com/fs/file2", "imop://abc.com/fs/file3"
        ]
    }
}