Skip to content

Instantly share code, notes, and snippets.

@graywolf336
Last active June 15, 2017 22:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save graywolf336/f4c6665f3fd14ae3c9c5055a83250222 to your computer and use it in GitHub Desktop.
Save graywolf336/f4c6665f3fd14ae3c9c5055a83250222 to your computer and use it in GitHub Desktop.
import { IRequest, IResponse, RequestMethod, ResponseStatus } from './interfaces/Webhook';
import { ISetting } from './interfaces/ISetting';
import { priority, PriorityValue } from './decorators/priority';
import { IMessage } from './interfaces/IMessage';
import { IUser } from './interfaces/IUser';
import { IRoom } from './interfaces/IRoom';
export class BaseRocketlet {
/**
* Create a new Rocketlet, this is called whenever the server starts up and initiates the Rocketlets. Note, your implementation of this class should call `super(name, id, version)` so we have it.
*/
constructor(public name: string, public id: number, public version: string) {
console.log(`Constructed the Rocketlet ${this.name} (${this.id}) v${this.version}!`);
}
/**
* Get the name of this Rocketlet.
*
* @return {string} the name
*/
getName() {
return this.name;
}
/**
* Get the version of this Rocketlet, using http://semver.org/.
*
* @return {string} the version
*/
getVersion() {
return this.version;
}
/**
* Get the ID of this Rocketlet, please see <link> for how to obtain an ID for your Rocketlet.
*
* @return {number} the ID
*/
getID() {
return this.version;
}
/**
* The Rocketlet should return an array of settings which it provies to the user to allow them to configure anything.
*
* @return {array} the settings this Rocketlet provides
*/
getSettings(): Array<ISetting> {
return new Array<ISetting>();
}
/**
* Gets the setting from the persistant storage, this will be provided to the Rocketlets and you don't have to implement it.
*
* @param id the id of the setting to retrieve
* @return the setting or undefined if it doesn't exist
*/
getSetting(id: string): ISetting {
return undefined;
}
/**
* Gets the value of the setting from the persistant storage, this will be provided to the Rocketlets and you don't have to implement it.
*
* @param id the id of the setting to get the value for
* @return the value of the setting if it is defined, will be undefined if it doesn't exist
*/
getSettingValue(id: string): any {
return undefined;
}
/**
* Method called when before the message is sent to other clients. Return the message object with your changes to it.
*
* @param room The room where the message is being sent to
* @param user The user who is sending the message
* @param message The message which is being sent
*/
@priority(PriorityValue.HIGHEST)
pre_messageSent(room: IRoom, user: IUser, message: IMessage): IMessage {
// Handle data before the message is saved to the database
return message;
}
/**
* Method called *after* the message is sent to the other clients.
*
* @param room The room where the message was sent to
* @param user The user who sent the message
* @param message The message which was sent
*/
@priority(PriorityValue.MONITOR)
post_messageSent(room: IRoom, user: IUser, message: IMessage): void {
// Handle data *after* the message is saved to the database
}
/**
* Called whenever the publically accessible url for this Rocketlet is called, if you handle the methods differently then split it out so your code doesn't get too big.
*
* @param method the method this was called with (GET, POST, etc)
* @param request the actual request made
* @return the response to send to the client
*/
webhook_event(method: RequestMethod, request: IRequest): IResponse {
return {
status: ResponseStatus.UNIMPLEMENTED
}
}
}

Rocketlets

Thanks to some creative brainstorming from @geekgonecrazy, I have coined this idea "Rocketlets" instead of plugins or integrations as those two terms are extremely generic and can mean a lot of other things to other people while using our own term will let us define what it means for us and other people.

The goal of Rocketlets is to allow people to fully customize how their Rocket.Chat instance works without having to fork Rocket.Chat along with Rocketlets being fully documented with how it works including the code being in TypeScript so that everything passed in has a type (and we can use decorators). The ability to customize a Rocket.Chat instance was started with integrations and how they now have different triggers (events) which can fire them, however even those are currently limited as they just allow reacting to a trigger after it has happened. With Rocketlets my idea is to have two different actions per trigger (event) which will allow them to customize the Rocket.Chat functionality.

Let's take the message sending event for example. A Rocketlet there can define pre_messageSent and post_messageSent methods. The pre_ methods will be called pre/before saving of the event and thus before the events are officially considered sent to others. The post_ methods will be called post/after the saving of the events. Thanks to using TypeScript, each method will be able to use a decorator which will specify the priority of the method on handling the event with a range from LOWEST to HIGHEST and then MONITOR. The lowest items will be called first and the highest will be called last, this way the highest priority items have the last say on an event than the lowest.

Incoming webhooks will also be merged into Rocketlets and they will be just another method that is call on the Rocketlet. When a Rocketlet gets created it will have a url generated for it which can be called (GET, POST, PUT, DELETE, etc) and use the data in along with providing data out. The method on the Rocketlet webhook_event will be called with two parameters passed, "method" and "request".

Now for the client, I want to allow Rocketlets to be able to fully utilize the action button type of message, along with defining tab bar functionality as you have highlighted in the above comments, along with full control over reactions and everything else. Another piece that Rocketlets will be able to do is provided new slash commands to the clients and show a preview of items to the client, see my comment here for an example.

Each Rocketlet will be able to provide a list of settings it provides to the user which the user can configure. The settings provided should have defaults unless the Rocketlet wants some to be configured before it can be enabled. This will allow for high configurability, for example let's say we create a GitHub Rocketlet and we want the user to be able to select which style of commits show up inside Rocket.Chat then they can select from a drop down either simple, extended, or advanced.

Eventually Rocketlets will get to the point that we can have a directory of Rocketlets that servers can click a single button to install them then elect to be updated automatically whenever a new Rocketlet comes out or manually approve the update. Each Rocketlet would then have a changelog so the users can see what changed between the versions inside of their Rocket.Chat. As a result of this global idea, each publicly available Rocketlet will need register with us, Rocket.Chat, to get an id however there will be a range of ids available for private usage so that private and public Rocketlets will never conflict with each other.

I am missing quite a bit of details. However, I wanted you to be aware of my idea as I noticied with your commit that our structure is basically the same and we would be duplicating work. I would be more than happy to work with you @mrsimpson so we can combine our efforts and get something crafted up that is simply awesome. Below is my base class idea for the server

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment