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

fix: code deletion when switching between multiple instances #81

Merged
merged 15 commits into from
Jan 4, 2024
3 changes: 2 additions & 1 deletion examples/firepad-monaco-example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ const init = function (): void {
trimAutoWhitespace: false,
});

const firepad = Firepad.fromMonacoWithFirestore(firestoreRef, editor, {
const firepad = Firepad.fromMonacoWithFirebase(firebaseRef, editor, {
questionId: "test-question-id",
userName: `Anonymous ${Math.floor(Math.random() * 100)}`,
defaultText: `// typescript Editing with Firepad!
function go() {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@hackerrank/firepad",
"description": "Collaborative text editing powered by Firebase",
"version": "0.8.4-beta",
"version": "0.8.4-dev-9",
"author": {
"email": "[email protected]",
"name": "Progyan Bhattacharya",
Expand Down
72 changes: 70 additions & 2 deletions src/firebase-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export class FirebaseAdapter implements IDatabaseAdapter {
protected _userId: UserIDType | null;
protected _userColor: string | null;
protected _userName: string | null;
protected _questionId: string | null;
protected _userCursor: ICursor | null;
protected _pendingReceivedRevisions: RevisionHistoryType;
protected _emitter: IEventEmitter | null;
Expand All @@ -110,7 +111,8 @@ export class FirebaseAdapter implements IDatabaseAdapter {
databaseRef: string | firebase.database.Reference,
userId: number | string,
userColor: string,
userName: string
userName: string,
questionId: string
) {
if (typeof databaseRef !== "object") {
databaseRef = firebase.database().ref(databaseRef);
Expand All @@ -122,6 +124,7 @@ export class FirebaseAdapter implements IDatabaseAdapter {
this._firebaseCallbacks = [];
this._zombie = false;
this._initialRevisions = false;
this._questionId = questionId;

// Add User Information
this.setUserId(userId);
Expand Down Expand Up @@ -181,6 +184,8 @@ export class FirebaseAdapter implements IDatabaseAdapter {
}

dispose(): void {
this._zombie = true;
MrSurana marked this conversation as resolved.
Show resolved Hide resolved

if (!this._ready) {
this.on(FirebaseAdapterEvent.Ready, () => {
this.dispose();
Expand All @@ -197,7 +202,6 @@ export class FirebaseAdapter implements IDatabaseAdapter {
this._databaseRef = null;
this._userRef = null;
this._document = null;
this._zombie = true;
}

getDocument(): ITextOperation | null {
Expand Down Expand Up @@ -292,6 +296,13 @@ export class FirebaseAdapter implements IDatabaseAdapter {
revisionId
] = revisionSnapshot.val() as RevisionType;

console.log(`[firepad] ${this._questionId} _historyChildAdded`, {
revisionId,
snapshot: revisionSnapshot.val(),
ready: this._ready,
timestamp: Date.now(),
});

if (this._ready) {
this._handlePendingReceivedRevisions();
}
Expand All @@ -302,6 +313,11 @@ export class FirebaseAdapter implements IDatabaseAdapter {
* @param revision - Intial revision to start monitoring from.
*/
protected _monitorHistoryStartingAt(revision: number): void {
console.log(`[firepad] ${this._questionId} _monitorHistoryStartingAt`, {
revision,
timestamp: Date.now(),
});

const historyRef = this._databaseRef!.child("history").startAt(
null,
this._revisionToId(revision)
Expand All @@ -327,9 +343,18 @@ export class FirebaseAdapter implements IDatabaseAdapter {
return;
}

console.log(`[firepad] ${this._questionId} _handleInitialRevisions`, {
timestamp: Date.now(),
});

Utils.validateFalse(this._ready, "Should not be called multiple times.");

if (!this._initialRevisions) {
console.log(
`[firepad] ${this._questionId} _handleInitialRevisions trigger() FirebaseAdapterEvent.InitialRevision`,
{ timestamp: Date.now() }
);

this._initialRevisions = true;
this._trigger(FirebaseAdapterEvent.InitialRevision);
}
Expand All @@ -340,6 +365,15 @@ export class FirebaseAdapter implements IDatabaseAdapter {
let revisionId = this._revisionToId(this._revision);
const pending = this._pendingReceivedRevisions;

console.log(
`[firepad] ${this._questionId} _handleInitialRevisions pending`,
{
revisionId,
pending: Object.assign({}, pending),
timestamp: Date.now(),
}
);

while (pending[revisionId] != null) {
const revision: IRevision | null = this._parseRevision(
pending[revisionId] as any
Expand All @@ -366,6 +400,11 @@ export class FirebaseAdapter implements IDatabaseAdapter {
this._trigger(FirebaseAdapterEvent.Operation, this._document!);
this._ready = true;

console.log(`[firepad] ${this._questionId} _handleInitialRevisions ready`, {
ready: this._ready,
timestamp: Date.now(),
});

setTimeout(() => {
this._trigger(FirebaseAdapterEvent.Ready, true);
});
Expand All @@ -380,6 +419,15 @@ export class FirebaseAdapter implements IDatabaseAdapter {
let revisionId = this._revisionToId(this._revision);
let triggerRetry = false;

console.log(
`[firepad] ${this._questionId} _handlePendingReceivedRevisions`,
{
revisionId,
pending: Object.assign({}, pending),
timestamp: Date.now(),
}
);

while (pending[revisionId] != null) {
this._revision++;

Expand Down Expand Up @@ -435,6 +483,15 @@ export class FirebaseAdapter implements IDatabaseAdapter {
revisionId = this._revisionToId(this._revision);
}

console.log(
`[firepad] ${this._questionId} _handlePendingReceivedRevisions complete`,
{
revision: this._revision,
pending: Object.assign({}, this._pendingReceivedRevisions),
timestamp: Date.now(),
}
);

if (triggerRetry) {
this._sent = null;
this._trigger(FirebaseAdapterEvent.Retry);
Expand All @@ -445,6 +502,12 @@ export class FirebaseAdapter implements IDatabaseAdapter {
operation: TextOperation,
callback: SendOperationCallbackType = Utils.noop
): void {
console.trace(`[firepad] ${this._questionId} sendOperation`, {
ready: this._ready,
operation,
timestamp: Date.now(),
});

// If we're not ready yet, do nothing right now, and trigger a retry when we're ready.
if (!this._ready) {
this.on(FirebaseAdapterEvent.Ready, () => {
Expand Down Expand Up @@ -473,6 +536,11 @@ export class FirebaseAdapter implements IDatabaseAdapter {
t: firebase.database.ServerValue.TIMESTAMP as number,
};

console.log(`[firepad] ${this._questionId} sendOperation revisionData`, {
revisionData,
timestamp: Date.now(),
});

this._doTransaction(revisionId, revisionData, callback);
}

Expand Down
3 changes: 2 additions & 1 deletion src/firepad-classic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ export default class FirepadClassic implements IFirepad {
databaseRef,
options.userId!,
options.userColor!,
options.userName!
options.userName!,
""
);
this._editorAdapter = new MonacoAdapter(editor, false);
this._editorClient = new EditorClient(
Expand Down
4 changes: 3 additions & 1 deletion src/firepad-monaco.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ export function fromMonacoWithFirebase(
options.userColor || Utils.colorFromUserId(userId.toString());
const userName: string = options.userName || userId.toString();
const defaultText: string = options.defaultText || editor.getValue();
const questionId: string = options.questionId || "";

let databaseAdapter: IDatabaseAdapter = new FirebaseAdapter(
databaseRef,
userId,
userColor,
userName
userName,
questionId
);

const editorAdapter = new MonacoAdapter(editor, false);
Expand Down
2 changes: 2 additions & 0 deletions src/firepad.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export interface IFirepadConstructorOptions {
userName?: string;
/** Default content of Firepad (optional) */
defaultText?: string;
/** TODO: remove this, only for debugging purpose */
questionId?: string;
}

export interface IFirepad extends Utils.IDisposable {
Expand Down
7 changes: 7 additions & 0 deletions src/monaco-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,13 @@ export class MonacoAdapter implements IEditorAdapter {
return;
}

console.log(`[firepad] setText`, {
range: model.getFullModelRange(),
newText: text,
oldText: model.getValue(),
timestamp: Date.now(),
});

model.applyEdits([
{
range: model.getFullModelRange(),
Expand Down
Loading