Skip to content

Commit

Permalink
chore: adding REST api for cloning and copy progress
Browse files Browse the repository at this point in the history
  • Loading branch information
sparkpunkd committed Jul 2, 2019
1 parent 9817068 commit c5082e4
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 293 deletions.
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,49 @@ All fragments can be cleared from the port by sending a DELETE request to the po

The `:start` parameter is the first frame in the port's timeline to wipe from and `:frames` is the count of frames to wipe forward from that point. The `:start` parameter defaults to `0`. If `:frames` is omitted, all frames from the given start offset to the current play position will be wiped, which will be no frames if `:start` is after the play head offset. The range of frames to wipe must not include the current play position. Check the Boolean-valued `wiped` property of the response message to see that whether the fragments were successfully cleared.

### Cloning clips

The Quantel systems have a mechanism to clone clips between servers, either within in the same zone or between servers in different zones (_inter-zone cloning_). Only the essence material that is missing from a particular disk pool is copied, meaning that a request to clone can be almost instantaneous where the material has already been duplicated. The Quantel gateway allows clones to be initiated and the subsequent copy progress of that or any other clone to be monitored.

To cause a clone, POST an object containing the source `zoneID` (number, not name), source `clipID` and destination `poolID` to `/:zoneID/copy`, as follows:

```JSON
{
"zoneID": 1000,
"clipID": 42,
"poolID": 12,
"priority": 15
}
```

The `priority` is a number between `0` for low and `15` for high that indicates a relative priority for this requested clone wrt other current copy operations. The response is similar, with an additional property `copyID` that is the clip ID of the newly created clip at the destination.

To view the status of a single copy operation for destination clip `:copyID`, use path:

/:zoneID/copy/:copyID

If the copy is still in progress or has been recently completed, an object of type `ClipProgress` is returned. If the copy completed a while ago or the clip does not exist, a `404 Not found` response is generated. Use this request in combination clip query (`.../clip/:clipID`) to determine if the clip exists.

```JSON
{
"type": "CopyProgress",
"clipID": 19,
"totalProtons": 225,
"protonsLeft": 116,
"secsLeft": 34,
"priority": 8,
"ticketed": false
}
```

_Protons_ are a unit of Quantel storage. The calculation `protonsLeft / totalProtons` can be used to provide a percentage complete of the copy. The Quantel system also provides a `secsLeft` property that is an estimation of how many seconds remain before the copy is complete. This value can go negative after the copy has completed, providing how many seconds ago did the copy complete.

Copies can be halted by deleting the destination clip.

### Deleting Clips

TO FOLLOW.

### Controlling the port

To control the PORT, POST trigger messages:
Expand Down
1 change: 1 addition & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"src/cxx/clip.cc",
"src/cxx/port.cc",
"src/cxx/control.cc",
"src/cxx/clone.cc",
"src/cxx/thumbs.cc",
"src/cxx/test_server.cc"
],
Expand Down
117 changes: 0 additions & 117 deletions src/cxx/clip.cc
Original file line number Diff line number Diff line change
Expand Up @@ -529,123 +529,6 @@ napi_value getFragments(napi_env env, napi_callback_info info) {
return promise;
}

// TODO leaving sync for now until requirements are clearer
void cloneIfNeededExecute(napi_env env, void* data) {
cloneIfNeededCarrier* c = (cloneIfNeededCarrier*) data;
Quentin::ZonePortal::_ptr_type zp;
CORBA::Boolean copyCreated;

try {
resolveZonePortalShared(c->isaIOR, &zp);

zp->cloneIfNeeded(c->clipID, c->poolID, 0,
c->highPriority ? Quentin::Port::HighPriority : Quentin::Port::StandardPriority,
-1, copyCreated); // TODO -1 means the cloned clip never expires. Is this OK?

c->copyCreated = copyCreated;
}
catch(CORBA::SystemException& ex) {
NAPI_REJECT_SYSTEM_EXCEPTION(ex);
}
catch(CORBA::Exception& ex) {
NAPI_REJECT_CORBA_EXCEPTION(ex);
}
catch(omniORB::fatalException& fe) {
NAPI_REJECT_FATAL_EXCEPTION(fe);
}
}

void cloneIfNeededComplete(napi_env env, napi_status asyncStatus, void* data) {
cloneIfNeededCarrier* c = (cloneIfNeededCarrier*) data;
napi_value result;

if (asyncStatus != napi_ok) {
c->status = asyncStatus;
c->errorMsg = "Clone if needed failed to complete.";
}
REJECT_STATUS;

c->status = napi_get_boolean(env, c->copyCreated, &result);
REJECT_STATUS;

napi_status status;
status = napi_resolve_deferred(env, c->_deferred, result);
FLOATING_STATUS;

tidyCarrier(env, c);
}

napi_value cloneIfNeeded(napi_env env, napi_callback_info info) {
cloneIfNeededCarrier* c = new cloneIfNeededCarrier;
napi_value promise, prop, resourceName;
napi_valuetype type;
bool isArray;
char* isaIOR = nullptr;
size_t iorLen = 0;

c->status = napi_create_promise(env, &c->_deferred, &promise);
REJECT_RETURN;

size_t argc = 2;
napi_value argv[2];
c->status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
REJECT_RETURN;

if (argc < 1) {
REJECT_ERROR_RETURN("Clone if needed must be provided with a IOR reference to an ISA server.",
QGW_INVALID_ARGS);
}
c->status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &iorLen);
REJECT_RETURN;
isaIOR = (char*) malloc((iorLen + 1) * sizeof(char));
c->status = napi_get_value_string_utf8(env, argv[0], isaIOR, iorLen + 1, &iorLen);
REJECT_RETURN;

c->isaIOR = isaIOR;

if (argc < 2) {
REJECT_ERROR_RETURN("Options object with clip ID and pool ID must be provided.",
QGW_INVALID_ARGS);
}
c->status = napi_typeof(env, argv[1], &type);
REJECT_RETURN;
c->status = napi_is_array(env, argv[1], &isArray);
REJECT_RETURN;
if (isArray || type != napi_object) {
REJECT_ERROR_RETURN("Argument must be an options object with clip ID and pool ID.",
QGW_INVALID_ARGS);
}

c->status = napi_get_named_property(env, argv[1], "clipID", &prop);
REJECT_RETURN;
c->status = napi_get_value_int32(env, prop, &c->clipID);
REJECT_RETURN;

c->status = napi_get_named_property(env, argv[1], "poolID", &prop);
REJECT_RETURN;
c->status = napi_get_value_int32(env, prop, &c->poolID);
REJECT_RETURN;

c->status = napi_get_named_property(env, argv[1], "highPriority", &prop);
REJECT_RETURN;
c->status = napi_typeof(env, prop, &type);
REJECT_RETURN;
if (type == napi_boolean) {
c->status = napi_get_value_bool(env, prop, &c->highPriority);
REJECT_RETURN;
}

c->status = napi_create_string_utf8(env, "CloneIfNeeded", NAPI_AUTO_LENGTH, &resourceName);
REJECT_RETURN;
c->status = napi_create_async_work(env, nullptr, resourceName, cloneIfNeededExecute,
cloneIfNeededComplete, c, &c->_request);
REJECT_RETURN;
c->status = napi_queue_async_work(env, c->_request);
REJECT_RETURN;

return promise;
}

void deletClipExecute(napi_env env, void* data) {
deleteClipCarrier* c = (deleteClipCarrier*) data;
Quentin::ZonePortal::_ptr_type zp;
Expand Down
12 changes: 0 additions & 12 deletions src/cxx/clip.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
napi_value getClipData(napi_env env, napi_callback_info info);
napi_value searchClips(napi_env env, napi_callback_info info);
napi_value getFragments(napi_env env, napi_callback_info info);
napi_value cloneIfNeeded(napi_env env, napi_callback_info info);
napi_value deleteClip(napi_env env, napi_callback_info info);

void getClipDataExecute(napi_env env, void* data);
Expand Down Expand Up @@ -89,17 +88,6 @@ struct getFragmentsCarrier : carrier {
~getFragmentsCarrier() { }
};

void cloneIfNeededExecute(napi_env env, void* data);
void cloneIfNeededComplete(napi_env env, napi_status asyncStatus, void* data);

struct cloneIfNeededCarrier : carrier {
int32_t clipID;
int32_t poolID;
bool highPriority = false;
bool copyCreated;
~cloneIfNeededCarrier() { }
};

void deletClipExecute(napi_env env, void* data);
void deleteClipComplete(napi_env env, napi_status asyncStatus, void* data);

Expand Down
9 changes: 6 additions & 3 deletions src/cxx/quantel_gateway.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "clip.h"
#include "port.h"
#include "control.h"
#include "clone.h"
#include "thumbs.h"
#include "test_server.h"

Expand Down Expand Up @@ -115,16 +116,18 @@ napi_value Init(napi_env env, napi_value exports) {
DECLARE_NAPI_METHOD("getFormatInfo", getFormatInfo),
DECLARE_NAPI_METHOD("getPortProperties", getPortProperties),
DECLARE_NAPI_METHOD("cloneInterZone", cloneInterZone),
DECLARE_NAPI_METHOD("getCopyRemaining", getCopyRemaining),
DECLARE_NAPI_METHOD("getCopiesRemaining", getCopiesRemaining),
DECLARE_NAPI_METHOD("runServer", runServer),
DECLARE_NAPI_METHOD("destroyOrb", destroyOrb),
{ "START", nullptr, nullptr, nullptr, nullptr, start, napi_enumerable, nullptr },
{ "STOP", nullptr, nullptr, nullptr, nullptr, stop, napi_enumerable, nullptr },
{ "STOP", nullptr, nullptr, nullptr, nullptr, stop, napi_enumerable, nullptr }, // 30
{ "JUMP", nullptr, nullptr, nullptr, nullptr, jump, napi_enumerable, nullptr },
{ "TRANSITION", nullptr, nullptr, nullptr, nullptr, transition, napi_enumerable, nullptr }, // 30
{ "TRANSITION", nullptr, nullptr, nullptr, nullptr, transition, napi_enumerable, nullptr },
{ "STANDARD", nullptr, nullptr, nullptr, nullptr, standard, napi_enumerable, nullptr},
{ "HIGH", nullptr, nullptr, nullptr, nullptr, high, napi_enumerable, nullptr},
};
status = napi_define_properties(env, exports, 32, desc);
status = napi_define_properties(env, exports, 34, desc);
CHECK_STATUS;

return exports;
Expand Down
147 changes: 0 additions & 147 deletions src/cxx/zone.cc
Original file line number Diff line number Diff line change
Expand Up @@ -616,150 +616,3 @@ napi_value getFormatInfo(napi_env env, napi_callback_info info) {

return promise;
}

void cloneInterZoneExecute(napi_env env, void* data) {
cloneInterZoneCarrier* c = (cloneInterZoneCarrier*) data;
Quentin::ZonePortal::_ptr_type zp;

try {
resolveZonePortalShared(c->isaIOR, &zp);

c->copyID = zp->cloneClipInterZone(c->zoneID, c->clipID, c->poolID, c->priority);
}
catch(CORBA::SystemException& ex) {
NAPI_REJECT_SYSTEM_EXCEPTION(ex);
}
catch(CORBA::Exception& ex) {
NAPI_REJECT_CORBA_EXCEPTION(ex);
}
catch(omniORB::fatalException& fe) {
NAPI_REJECT_FATAL_EXCEPTION(fe);
}
}

void cloneInterZoneComplete(napi_env env, napi_status asyncStatus, void* data) {
cloneInterZoneCarrier* c = (cloneInterZoneCarrier*) data;
napi_value result, prop;

if (asyncStatus != napi_ok) {
c->status = asyncStatus;
c->errorMsg = "Clone inter zone failed to complete.";
}
REJECT_STATUS;

c->status = napi_create_object(env, &result);
REJECT_STATUS;

c->status = napi_create_string_utf8(env, "CloneInterZoneResult", NAPI_AUTO_LENGTH, &prop);
REJECT_STATUS;
c->status = napi_set_named_property(env, result, "type", prop);
REJECT_STATUS;

c->status = napi_create_int32(env, c->zoneID , &prop);
REJECT_STATUS;
c->status = napi_set_named_property(env, result, "zoneID", prop);
REJECT_STATUS;

c->status = napi_create_int32(env, c->clipID , &prop);
REJECT_STATUS;
c->status = napi_set_named_property(env, result, "clipID", prop);
REJECT_STATUS;

c->status = napi_create_int32(env, c->poolID , &prop);
REJECT_STATUS;
c->status = napi_set_named_property(env, result, "poolID", prop);
REJECT_STATUS;

c->status = napi_create_int32(env, c->priority , &prop);
REJECT_STATUS;
c->status = napi_set_named_property(env, result, "priority", prop);
REJECT_STATUS;

c->status = napi_create_int32(env, c->copyID, &prop);
REJECT_STATUS;
c->status = napi_set_named_property(env, result, "copyID", prop);
REJECT_STATUS;

napi_status status;
status = napi_resolve_deferred(env, c->_deferred, result);
FLOATING_STATUS;

tidyCarrier(env, c);
}

napi_value cloneInterZone(napi_env env, napi_callback_info info) {
cloneInterZoneCarrier* c = new cloneInterZoneCarrier;
napi_value promise, resourceName, prop, options;
napi_valuetype type;
bool isArray;
char* isaIOR = nullptr;
size_t iorLen = 0;

c->status = napi_create_promise(env, &c->_deferred, &promise);
REJECT_RETURN;

size_t argc = 2;
napi_value argv[2];
c->status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
REJECT_RETURN;

if (argc < 1) {
REJECT_ERROR_RETURN("Clone inter zone must be provided with a IOR reference to an ISA server.",
QGW_INVALID_ARGS);
}
c->status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &iorLen);
REJECT_RETURN;
isaIOR = (char*) malloc((iorLen + 1) * sizeof(char));
c->status = napi_get_value_string_utf8(env, argv[0], isaIOR, iorLen + 1, &iorLen);
REJECT_RETURN;

c->isaIOR = isaIOR;

if (argc < 2) {
REJECT_ERROR_RETURN("Clone inter zone must be provided with an options object containing source zone ID, source clip ID and destination pool ID.",
QGW_INVALID_ARGS);
}
c->status = napi_typeof(env, argv[1], &type);
REJECT_RETURN;
c->status = napi_is_array(env, argv[1], &isArray);
REJECT_RETURN;
if (isArray || type != napi_object) {
REJECT_ERROR_RETURN("Argument must be an options object with a source zone ID, source clip ID and destination pool ID",
QGW_INVALID_ARGS);
}

options = argv[1];
c->status = napi_get_named_property(env, options, "zoneID", &prop);
REJECT_RETURN;
c->status = napi_get_value_int32(env, prop, (int32_t*) &c->zoneID);
REJECT_RETURN;

c->status = napi_get_named_property(env, options, "clipID", &prop);
REJECT_RETURN;
c->status = napi_get_value_int32(env, prop, (int32_t*) &c->clipID);
REJECT_RETURN;

c->status = napi_get_named_property(env, options, "poolID", &prop);
REJECT_RETURN;
c->status = napi_get_value_int32(env, prop, (int32_t*) &c->poolID);
REJECT_RETURN;

c->status = napi_get_named_property(env, options, "priority", &prop);
REJECT_RETURN;
c->status = napi_typeof(env, prop, &type);
REJECT_RETURN;
if (type == napi_number) {
c->status = napi_get_value_int32(env, prop, (int32_t*) &c->priority);
REJECT_RETURN;
}

c->status = napi_create_string_utf8(env, "CloneInterZone", NAPI_AUTO_LENGTH, &resourceName);
REJECT_RETURN;
c->status = napi_create_async_work(env, nullptr, resourceName, cloneInterZoneExecute,
cloneInterZoneComplete, c, &c->_request);
REJECT_RETURN;
c->status = napi_queue_async_work(env, c->_request);
REJECT_RETURN;

return promise;
}
Loading

0 comments on commit c5082e4

Please sign in to comment.