Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rest lifecycle status RSL8 #985

Merged
merged 10 commits into from
May 27, 2022
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ ably-js.iml
node_modules
npm-debug.log
.tool-versions
/browser/static
build/
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,16 @@ channel.presence.history(function(err, messagesPage) { // PaginatedResult
channel.history({start: ..., end: ..., limit: ..., direction: ...}, function(err, messagesPage) { ...});
```

### Getting the status of a channel

```javascript
channel.status(function(err, channelDetails) {
channelDetails.channelId // The name of the channel
channelDetails.status.isActive // A boolean indicating whether the channel is active
channelDetails.status.occupancy // Contains metadata relating to the occupants of the channel
});
```

### Generate Token and Token Request

See https://www.ably.com/docs/general/authentication for an
Expand Down Expand Up @@ -518,6 +528,10 @@ const ablyRestPromiseExample = async () => {
const history = await channel.history({ limit: 25 });
console.log(await history.current());

// Getting the status of a channel
const channelDetails = await channel.status();
console.log(channelDetails);

// Requesting a token
const token = await client.auth.requestToken(tokenParams);

Expand All @@ -531,7 +545,7 @@ const ablyRestPromiseExample = async () => {
// Fetching the Ably service time
const time = await client.time();
console.log(`Ably service time: ${time}`);

client.close();
};

Expand Down
25 changes: 25 additions & 0 deletions ably.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,29 @@ declare namespace Types {

type Transport = 'web_socket' | 'xhr_streaming' | 'xhr_polling' | 'jsonp' | 'comet';

interface ChannelDetails {
channelId: string;
status: ChannelStatus;
}

interface ChannelStatus {
isActive: boolean;
occupancy: ChannelOccupancy;
}

interface ChannelOccupancy {
metrics: ChannelMetrics;
}

interface ChannelMetrics {
connections: number;
presenceConnections: number;
presenceMembers: number;
presenceSubscribers: number;
publishers: number;
subscribers: number;
}

// Interfaces
interface ClientOptions extends AuthOptions {
/**
Expand Down Expand Up @@ -650,13 +673,15 @@ declare namespace Types {
publish(messages: any, callback?: errorCallback): void;
publish(name: string, messages: any, callback?: errorCallback): void;
publish(name: string, messages: any, options?: PublishOptions, callback?: errorCallback): void;
status(callback: StandardCallback<ChannelDetails>): void;
}

class ChannelPromise extends ChannelBase {
presence: PresencePromise;
history: (params?: RestHistoryParams) => Promise<PaginatedResult<Message>>;
publish(messages: any, options?: PublishOptions): Promise<void>;
publish(name: string, messages: any, options?: PublishOptions): Promise<void>;
status(): Promise<ChannelDetails>;
}

class RealtimeChannelBase extends EventEmitter<channelEventCallback, ChannelStateChange, ChannelEvent> {
Expand Down
14 changes: 13 additions & 1 deletion src/common/lib/client/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import ErrorInfo from '../types/errorinfo';
import PaginatedResource, { PaginatedResult } from './paginatedresource';
import Resource, { ResourceCallback } from './resource';
import { ChannelOptions } from '../../types/channel';
import { PaginatedResultCallback } from '../../types/utils';
import { PaginatedResultCallback, StandardCallback } from '../../types/utils';
import Rest from './rest';
import Realtime from './realtime';
import * as API from '../../../../ably';
import Platform from 'common/platform';

interface RestHistoryParams {
Expand Down Expand Up @@ -189,6 +190,17 @@ class Channel extends EventEmitter {
_publish(requestBody: unknown, headers: Record<string, string>, params: any, callback: ResourceCallback): void {
Resource.post(this.rest, this.basePath + '/messages', requestBody, headers, params, null, callback);
}

status(callback?: StandardCallback<API.Types.ChannelDetails>): void | Promise<API.Types.ChannelDetails> {
if (typeof callback !== 'function' && this.rest.options.promises) {
return Utils.promisify(this, 'status', []);
}

const format = this.rest.options.useBinaryProtocol ? Utils.Format.msgpack : Utils.Format.json;
const headers = Utils.defaultPostHeaders(format);

Resource.get<API.Types.ChannelDetails>(this.rest, this.basePath, headers, {}, format, callback || noop);
}
}

export default Channel;
20 changes: 10 additions & 10 deletions src/common/lib/client/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function withAuthDetails(
}
}

function unenvelope(callback: ResourceCallback, format: Utils.Format | null): ResourceCallback {
function unenvelope<T>(callback: ResourceCallback<T>, format: Utils.Format | null): ResourceCallback<T> {
return (err, body, outerHeaders, unpacked, outerStatusCode) => {
if (err && !body) {
callback(err);
Expand Down Expand Up @@ -85,8 +85,8 @@ function urlFromPathAndParams(path: string, params: Record<string, any>) {
return path + (params ? '?' : '') + paramString(params);
}

function logResponseHandler(
callback: ResourceCallback,
function logResponseHandler<T>(
callback: ResourceCallback<T>,
method: HttpMethods,
path: string,
params: Record<string, string>
Expand All @@ -113,27 +113,27 @@ function logResponseHandler(
);
}
if (callback) {
callback(err, body, headers, unpacked, statusCode);
callback(err, body as T, headers, unpacked, statusCode);
}
};
}

export type ResourceCallback = (
export type ResourceCallback<T = unknown> = (
err: ErrorInfo | null,
body?: unknown,
body?: T,
headers?: Record<string, string>,
unpacked?: boolean,
statusCode?: number
) => void;

class Resource {
static get(
static get<T = unknown>(
rest: Rest,
path: string,
headers: Record<string, string>,
params: Record<string, any>,
envelope: Utils.Format | null,
callback: ResourceCallback
callback: ResourceCallback<T>
): void {
Resource.do(HttpMethods.Get, rest, path, null, headers, params, envelope, callback);
}
Expand Down Expand Up @@ -185,15 +185,15 @@ class Resource {
Resource.do(HttpMethods.Put, rest, path, body, headers, params, envelope, callback);
}

static do(
static do<T>(
method: HttpMethods,
rest: Rest,
path: string,
body: unknown,
headers: Record<string, string>,
params: Record<string, any>,
envelope: Utils.Format | null,
callback: ResourceCallback
callback: ResourceCallback<T>
): void {
if (Logger.shouldLog(Logger.LOG_MICRO)) {
callback = logResponseHandler(callback, method, path, params);
Expand Down
71 changes: 71 additions & 0 deletions test/rest/status.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
'use strict';

define(['shared_helper', 'chai'], function (helper, chai) {
var rest;
var utils = helper.Utils;
var expect = chai.expect;

// RSL8
describe('rest/status', function () {
owenpearson marked this conversation as resolved.
Show resolved Hide resolved
this.timeout(30 * 1000);

before(function (done) {
helper.setupApp(function (err) {
if (err) {
done(err);
return;
}
rest = helper.AblyRest();
done();
});
});

it('status0', function (done) {
var channel = rest.channels.get('status0');
channel.status(function (err, channelDetails) {
try {
expect(channelDetails.channelId).to.equal('status0');
expect(channelDetails.status.isActive).to.be.a('boolean');
var metrics = channelDetails.status.occupancy.metrics;
expect(metrics.connections).to.be.a('number');
expect(metrics.presenceConnections).to.be.a('number');
expect(metrics.presenceMembers).to.be.a('number');
expect(metrics.presenceSubscribers).to.be.a('number');
expect(metrics.publishers).to.be.a('number');
expect(metrics.subscribers).to.be.a('number');
done();
} catch (err) {
done(err);
}
});
});

if (typeof Promise !== 'undefined') {
it('statusPromise', function (done) {
var rest = helper.AblyRest({ promises: true });
var channel = rest.channels.get('statusPromise');
channel
.status()
.then(function (channelDetails) {
try {
expect(channelDetails.channelId).to.equal('statusPromise');
expect(channelDetails.status.isActive).to.be.a('boolean');
var metrics = channelDetails.status.occupancy.metrics;
expect(metrics.connections).to.be.a('number');
expect(metrics.presenceConnections).to.be.a('number');
expect(metrics.presenceMembers).to.be.a('number');
expect(metrics.presenceSubscribers).to.be.a('number');
expect(metrics.publishers).to.be.a('number');
expect(metrics.subscribers).to.be.a('number');
done();
} catch (err) {
done(err);
}
})
['catch'](function (err) {
done(err);
});
});
}
});
});