Prevent state collisions

Previously if you opened different workspaces that had the same filesystem path
(for example if you have /home/coder on two different machines that are both
accessed through the same host) they would conflict with each other.  This
ensures that different browser paths will be unique (for example /workspace1 and
/workspace2).

The easiest way to test is to open files in the same workspace using both / and
/vscode and make sure they are not interacting with each other.

It should also migrate old databases which can be tested by opening in an old
code-server.

This has e2e tests.

Index: code-server/lib/vscode/src/vs/platform/storage/browser/storageService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/storage/browser/storageService.ts
+++ code-server/lib/vscode/src/vs/platform/storage/browser/storageService.ts
@@ -13,6 +13,7 @@ import { InMemoryStorageDatabase, isStor
 import { ILogService } from 'vs/platform/log/common/log';
 import { AbstractStorageService, IS_NEW_KEY, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
 import { IAnyWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
+import { hash } from 'vs/base/common/hash';
 
 export class BrowserStorageService extends AbstractStorageService {
 
@@ -36,7 +37,11 @@ export class BrowserStorageService exten
 	}
 
 	private getId(scope: StorageScope): string {
-		return scope === StorageScope.GLOBAL ? 'global' : this.payload.id;
+		// Add a unique ID based on the current path for per-workspace databases.
+		// This prevents workspaces on different machines that share the same domain
+		// and file path from colliding (since it does not appear IndexedDB can be
+		// scoped to a path) as long as they are hosted on different paths.
+		return scope === StorageScope.GLOBAL ? 'global' : (this.payload.id + '-' + hash(location.pathname.toString().replace(/\/$/, "")).toString(16));
 	}
 
 	protected async doInitialize(): Promise<void> {
@@ -75,6 +80,21 @@ export class BrowserStorageService exten
 		const firstWorkspaceOpen = this.workspaceStorage.getBoolean(IS_NEW_KEY);
 		if (firstWorkspaceOpen === undefined) {
 			this.workspaceStorage.set(IS_NEW_KEY, true);
+			// Migrate the old database.
+			let db: IIndexedDBStorageDatabase | undefined
+			try {
+				db = await IndexedDBStorageDatabase.create({ id: this.payload.id }, this.logService)
+				const items = await db.getItems()
+				for (const [key, value] of items) {
+					this.workspaceStorage.set(key, value);
+				}
+			} catch (error) {
+				this.logService.error(`[IndexedDB Storage ${this.payload.id}] migrate error: ${toErrorMessage(error)}`);
+			} finally {
+				if (db) {
+					db.close()
+				}
+			}
 		} else if (firstWorkspaceOpen) {
 			this.workspaceStorage.set(IS_NEW_KEY, false);
 		}
