Builder, Creator and Creation

Builder

Builder is a creational design pattern that lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code. (Source: Builder - refactoring.guru)

You might think of creating a giant constructor with lots of parameters, which may also measure up to the above work. But it's against the No Long Parameter List rule.

A real-life example 👉IRoomBuilder, RoomBuilder

Creator

Creator is a concept from the creational design pattern - Abstract Factory.

The Abstract Factory pattern lets you produce families of related objects without specifying their concrete classes. (Source: Abstract Factory - refactoring.guru)

A real-life example 👉 ILivechatCreator (It seems that we do not apply an abstract factory pattern but a factory pattern here. Because there are no various types of livechat rooms.)

Creation

The Creation is the basic data for building a complex object. A constructor or a Builder will create more complex objects based on the Creation that passed to it.

A real-life example 👉 User

Edit nginx configurations to reverse proxy jupyterlab

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

server {
...
location / {
proxy_pass http://jupyter;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~* /(api/kernels/[^/]+/(channels|iopub|shell|stdin)|terminals/websocket)/? {
proxy_pass http://jupyter;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
...
}

Reset jupyterlab to the default status

1
2
rm ~/.jupyter/lab/workspacess/*
jupyter lab rebuild

How to create a new event handler in apps-engine repo?

Here, we put LivechatRoomClosed event as an example:

Apps-engine side

  1. Update the AppMethod enum which is under the definition/metadata directory. We will add a new method EXECUTELIVECHATROOMCLOSEDHANDLER:
1
2
3
4
...
// Livechat
EXECUTE_LIVECHAT_ROOM_CLOSED_HANDLER = 'executeLivechatRoomClosedHandler',
...
  1. Also we need to update the AppInterface enum which is under the server/compiler/AppImplements directory:
1
2
3
4
...
// Livechat
ILivechatRoomClosedHander = 'ILivechatRoomClosedHander',
...
  1. Create an interface called ILivechatRoomClosedHander.ts under the definition/livechat, its content can be similar to this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { IHttp, IPersistence, IRead } from '../accessors';
import { AppMethod } from '../metadata';
import { ILivechatRoom } from './ILivechatRoom';

/**
* Handler called after a livechat room is closed.
*/
export interface ILivechatRoomClosedHander {
/**
* Method called *after* a livechat room is closed.
*
* @param livechatRoom The livechat room which is closed.
* @param read An accessor to the environment
* @param http An accessor to the outside world
* @param persistence An accessor to the App's persistence
*/
[AppMethod.EXECUTE_LIVECHAT_ROOM_CLOSED_HANDLER](data: ILivechatRoom, read: IRead, http: IHttp, persistence: IPersistence): Promise<void>;
}
  1. Edit AppListenerManager which is under the server/manager directory:

    • Add a new case into executeListener method:

    1
    2
    3
    4
    5
    6
    ...
    // Livechat
    case AppInterface.ILivechatRoomClosedHander:
    this.executeLivechatRoomClosed(data as ILivechatRoom);
    return;
    ...

    • Add executeLivechatRoomClosed method to resolve the events:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    private async executeLivechatRoomClosed(data: ILivechatRoom): Promise<void> {
    const cfLivechatRoom = Utilities.deepCloneAndFreeze(data);

    for (const appId of this.listeners.get(AppInterface.ILivechatRoomClosedHander)) {
    const app = this.manager.getOneById(appId);

    if (!app.hasMethod(AppMethod.EXECUTE_LIVECHAT_ROOM_CLOSED_HANDLER)) {
    continue;
    }

    await app.call(AppMethod.EXECUTE_LIVECHAT_ROOM_CLOSED_HANDLER,
    cfLivechatRoom,
    this.am.getReader(appId),
    this.am.getHttp(appId),
    this.am.getPersistence(appId),
    );
    }
    }

Get a list of all git commits, including the lost ones

I accidentally did some unattached commits to the repository and couldn't find them later.

Thanks to the google-oriented programming, I finally find the way to get the lost commits back ✌️

We can use git log --reflog to list all recent commits and then cherry-pick each commit to the current branch.

References: Get a list of all git commits, including the lost ones

Weekly Pair Programming 1: Early return and async/await

Today, I had a pair programming session with my mentor Douglas, which is an awesome experience for me. I learned a lot of advanced programming knowledge from this pair session. And below are some of the notes that deserved to be mentioned:

Remove unused settings from Rocket.Chat

I was going to add a new setting item - Apps_Game_Center_enabled into the settings page, but some extra unwanted settings were also added to this group. Although, I've already removed these items from the MongoDB. I still saw them in the settings page, it's so weird...

By diving into the codebase, I finally found that we are using PrivateSettingsCachedCollection to cache the settings. With this finding, I solved the issue with the following code:

Inject the following code below

1
2
3
4
...
const rcSettings = settings.collectionPrivate.find({ group: groupId }, { sort: { section: 1, sorter: 1, i18nLabel: 1 } }).fetch();
const sections = {};
...

1
2
3
4
5
6
7
8
9
10
11
12
13
// the code to be injected
rcSettings.forEach(({ _id, section }) => {
const group = 'Apps';
const whitelist = [
'Apps_Framework_enabled',
'Apps_Framework_Development_Mode',
'Apps_Game_Center_enabled',
];

if (section === group && !whitelist.includes(_id)) {
settings.collectionPrivate.remove({ _id });
}
});

Lastly, run meteor shell and .reload to reload the project, you will find the extra settings have be removed from the collection 😆

Something went wrong installing the sharp module

Sometimes, when I switch to a new branch of Rocket.Chat I need to suffer pains from the native modules rebuilding. The sharp module for example, maybe possibly built unsuccessfully.

You will receive an error similar to Something went wrong installing the sharp module. The solution is to run the command meteor npm rebuild to rebuild modules. Hopefully, you can see some detailed errors during the recompiling/building and you can solve it easily.

Bundle ES modules to browser with Browserify

2019-11-12 Update:

We can use gulp to simplify the workflow:

1
2
3
4
5
6
const bundle_sdk = shell.task([
`echo "window.AppsEngineUIClient = require('./AppsEngineUIClient').AppsEngineUIClient;" > client/glue.js`,
'cd client && npx browserify glue.js | npx uglifyjs > AppsEngineUIClient.min.js'
]);

gulp.task('bundle', bundle_sdk);

Below is the original post:

Firstly, install related dependencies with npm:

1
npm i -g browserify uglify-es

Then, create a glue script (here we can name it main.js) to inject the ES module to be a window property.

1
window.AppsEngineUIClient = require('./AppsEngineUIClient').AppsEngineUIClient;

For the last step, use browserify to bundle modules and uglifyjs to minify the script (remove all comments for example).

1
browserify main.js | uglifyjs > AppsEngineUIClient.min.js

Try the docker for the first time

  • 2019-11-9

docker login

Log in to a Docker registry. If no server is specified, the default is defined by the daemon.

-p, --password string

Password

-u, --username string

Username

Example

1
docker login -u lolimay

docker build

build an image from a Dockerfile

-t, --tag list

Name and optionally a tag in the 'name:tag' format. If the tag is not specified, use latest by default.

Example

1
docker build -t lolimay/cheers2019:test .

docker run

Run a command in a new container

-i, --interactive

Keep STDIN open even if not attached

-t, --tty

Allocate a pseudo-TTY

--rm

Automatically remove the container when it exits

Example

1
docker run -it --rm lolimay/cheers2019:test

docker push

Push an image or a repository to a registry

Example

1
docker push lolimay/cheers2019