Skip to content
This repository has been archived by the owner on Apr 22, 2024. It is now read-only.

Commit

Permalink
feat: add gnome 43 support
Browse files Browse the repository at this point in the history
  • Loading branch information
oae committed Sep 19, 2022
1 parent 092983e commit ab55c43
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 240 deletions.
22 changes: 22 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"workbench.colorCustomizations": {
"activityBar.activeBackground": "#1e593f",
"activityBar.background": "#1e593f",
"activityBar.foreground": "#e7e7e7",
"activityBar.inactiveForeground": "#e7e7e799",
"activityBarBadge.background": "#221030",
"activityBarBadge.foreground": "#e7e7e7",
"commandCenter.border": "#e7e7e799",
"sash.hoverBorder": "#1e593f",
"statusBar.background": "#113324",
"statusBar.foreground": "#e7e7e7",
"statusBarItem.hoverBackground": "#1e593f",
"statusBarItem.remoteBackground": "#113324",
"statusBarItem.remoteForeground": "#e7e7e7",
"titleBar.activeBackground": "#113324",
"titleBar.activeForeground": "#e7e7e7",
"titleBar.inactiveBackground": "#11332499",
"titleBar.inactiveForeground": "#e7e7e799"
},
"peacock.color": "#113324"
}
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"@gi-types/gtk4": "^4.6.1",
"@gi-types/meta10": "^10.0.1",
"@gi-types/shell0": "^0.1.1",
"@gi-types/soup2": "^2.74.1",
"@gi-types/soup3": "^3.0.1",
"@gi-types/st1": "^1.0.1",
"@gi.ts/cli": "^1.5.7",
"@gi.ts/lib": "^1.5.9",
Expand All @@ -66,7 +66,6 @@
},
"dependencies": {
"events": "^3.3.0",
"fast-xml-parser": "^3.21.0",
"grest": "^1.2.0"
"fast-xml-parser": "^3.21.0"
}
}
2 changes: 1 addition & 1 deletion resources/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"version": 999,
"settings-schema": "org.gnome.shell.extensions.extensions-sync",
"url": "https://github.com/oae/gnome-shell-extensions-sync",
"shell-version": ["40", "41", "42"]
"shell-version": ["42", "43"]
}
7 changes: 1 addition & 6 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,12 @@ const globals = {
'@gi-types/st1': 'imports.gi.St',
'@gi-types/shell0': 'imports.gi.Shell',
'@gi-types/meta10': 'imports.gi.Meta',
'@gi-types/soup2': 'imports.gi.Soup',
'@gi-types/soup3': 'imports.gi.Soup',
'@gi-types/gobject2': 'imports.gi.GObject',
};

const external = Object.keys(globals);

const banner = [
'imports.gi.versions.Gtk = \'4.0\';',
].join('\n');

const prefsFooter = [
'var init = prefs.init;',
'var buildPrefsWidget = prefs.buildPrefsWidget;',
Expand Down Expand Up @@ -77,7 +73,6 @@ export default [
format: 'iife',
exports: 'default',
name: 'prefs',
banner,
footer: prefsFooter,
globals,
},
Expand Down
56 changes: 33 additions & 23 deletions src/api/providers/github.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SyncData } from '@esync/data';
import { logger } from '@esync/utils';
import { Context as request } from 'grest/src/app/Context/Context';
import { Bytes, PRIORITY_DEFAULT } from '@gi-types/glib2';
import { Message, Session, Status, status_get_phrase } from '@gi-types/soup3';
import { SyncOperationStatus, SyncProvider } from '../types';

const debug = logger('github');
Expand All @@ -10,10 +11,12 @@ export class Github implements SyncProvider {

private gistId: string;
private userToken: string;
private session: Session;

constructor(gistId: string, userToken: string) {
this.gistId = gistId;
this.userToken = userToken;
this.session = new Session();
}

async save(syncData: SyncData): Promise<SyncOperationStatus> {
Expand All @@ -26,38 +29,45 @@ export class Github implements SyncProvider {
};
}, {});

const { status } = await request.fetch(`${Github.GIST_API_URL}/${this.gistId}`, {
headers: {
'User-Agent': 'Mozilla/5.0',
Authorization: `token ${this.userToken}`,
},
body: {
description: 'Extensions Sync',
files,
},
method: 'PATCH',
const message = Message.new('PATCH', `${Github.GIST_API_URL}/${this.gistId}`);
message.request_headers.append('User-Agent', 'Mozilla/5.0');
message.request_headers.append('Authorization', `token ${this.userToken}`);
const requestBody = JSON.stringify({
description: 'Extensions Sync',
files,
});
message.set_request_body_from_bytes('application/json', new Bytes(imports.byteArray.fromString(requestBody)));
await this.session.send_and_read_async(message, PRIORITY_DEFAULT, null);

if (status !== 200) {
throw new Error(`failed to save data to ${this.getName()}. Server status: ${status}`);
const { statusCode } = message;
const phrase = status_get_phrase(statusCode);
if (statusCode !== Status.OK) {
throw new Error(`failed to save data to ${this.getName()}. Server status: ${phrase}`);
}

return status === 200 ? SyncOperationStatus.SUCCESS : SyncOperationStatus.FAIL;
return SyncOperationStatus.SUCCESS;
}

async read(): Promise<SyncData> {
const { body, status } = await request.fetch(`${Github.GIST_API_URL}/${this.gistId}`, {
headers: {
'User-Agent': 'Mozilla/5.0',
Authorization: `token ${this.userToken}`,
},
method: 'GET',
});
const message = Message.new('GET', `${Github.GIST_API_URL}/${this.gistId}`);
message.request_headers.append('User-Agent', 'Mozilla/5.0');
message.request_headers.append('Authorization', `token ${this.userToken}`);

if (status !== 200) {
throw new Error(`failed to read data from ${this.getName()}. Server status: ${status}`);
const bytes = await this.session.send_and_read_async(message, PRIORITY_DEFAULT, null);
const { statusCode } = message;
const phrase = status_get_phrase(statusCode);
if (statusCode !== Status.OK) {
throw new Error(`failed to read data from ${this.getName()}. Server status: ${phrase}`);
}

const data = bytes.get_data();
if (data === null) {
throw new Error(`failed to read data from ${this.getName()}. Empty response`);
}

const json = imports.byteArray.toString(data);
const body = JSON.parse(json);

const syncData: SyncData = Object.keys(body.files).reduce(
(acc, key) => {
try {
Expand Down
59 changes: 34 additions & 25 deletions src/api/providers/gitlab.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,62 @@
import { SyncData } from '@esync/data';
import { Context as request } from 'grest/src/app/Context/Context';
import { Bytes, PRIORITY_DEFAULT } from '@gi-types/glib2';
import { Message, Session, Status, status_get_phrase } from '@gi-types/soup3';
import { SyncOperationStatus, SyncProvider } from '../types';

export class Gitlab implements SyncProvider {
private static SNIPPETS_API_URL = 'https://gitlab.com/api/v4/snippets';

private snippetId: string;
private userToken: string;
private session: Session;

constructor(snippetId: string, userToken: string) {
this.snippetId = snippetId;
this.userToken = userToken;
this.session = new Session();
}

async save(syncData: SyncData): Promise<SyncOperationStatus> {
const { status } = await request.fetch(`${Gitlab.SNIPPETS_API_URL}/${this.snippetId}`, {
headers: {
'User-Agent': 'Mozilla/5.0',
'PRIVATE-TOKEN': `${this.userToken}`,
'Content-Type': 'application/json',
},
body: {
title: 'Extensions Sync',
content: JSON.stringify(syncData),
},
method: 'PUT',
const message = Message.new('PUT', `${Gitlab.SNIPPETS_API_URL}/${this.snippetId}`);
message.request_headers.append('User-Agent', 'Mozilla/5.0');
message.request_headers.append('PRIVATE-TOKEN', `${this.userToken}`);
const requestBody = JSON.stringify({
title: 'Extensions Sync',
content: JSON.stringify(syncData),
});
message.set_request_body_from_bytes('application/json', new Bytes(imports.byteArray.fromString(requestBody)));
await this.session.send_and_read_async(message, PRIORITY_DEFAULT, null);

if (status !== 200) {
throw new Error(`failed to save data to ${this.getName()}. Server status: ${status}`);
const { statusCode } = message;
const phrase = status_get_phrase(statusCode);
if (statusCode !== Status.OK) {
throw new Error(`failed to save data to ${this.getName()}. Server status: ${phrase}`);
}

return status === 200 ? SyncOperationStatus.SUCCESS : SyncOperationStatus.FAIL;
return SyncOperationStatus.SUCCESS;
}

async read(): Promise<SyncData> {
const { body, status } = await request.fetch(`${Gitlab.SNIPPETS_API_URL}/${this.snippetId}/raw`, {
headers: {
'User-Agent': 'Mozilla/5.0',
'PRIVATE-TOKEN': `${this.userToken}`,
},
method: 'GET',
});
const message = Message.new('GET', `${Gitlab.SNIPPETS_API_URL}/${this.snippetId}/raw`);
message.request_headers.append('User-Agent', 'Mozilla/5.0');
message.request_headers.append('PRIVATE-TOKEN', `${this.userToken}`);

const bytes = await this.session.send_and_read_async(message, PRIORITY_DEFAULT, null);
const { statusCode } = message;
const phrase = status_get_phrase(statusCode);
if (statusCode !== Status.OK) {
throw new Error(`failed to read data from ${this.getName()}. Server status: ${phrase}`);
}

if (status !== 200) {
throw new Error(`failed to read data from ${this.getName()}. Server status: ${status}`);
const data = bytes.get_data();
if (data === null) {
throw new Error(`failed to read data from ${this.getName()}. Empty response`);
}

return body;
const json = imports.byteArray.toString(data);
const syncData = JSON.parse(json);

return syncData;
}

getName(): string {
Expand Down
95 changes: 29 additions & 66 deletions src/data/providers/extensions/utils.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
import { ExtensionType, getCurrentExtension, readDconfData, ShellExtension } from '@esync/shell';
import { execute, logger } from '@esync/utils';
import { File } from '@gi-types/gio2';
import {
build_filenamev,
ByteArray,
child_watch_add,
file_get_contents,
get_user_data_dir,
PRIORITY_DEFAULT,
SpawnFlags,
spawn_async,
spawn_close_pid,
} from '@gi-types/glib2';
import { form_encode_hash, Message, Session, Status, status_get_phrase, URI } from '@gi-types/soup2';
import { File, Subprocess, SubprocessFlags } from '@gi-types/gio2';
import { build_filenamev, file_get_contents, get_user_data_dir, PRIORITY_DEFAULT } from '@gi-types/glib2';
import { form_encode_hash, Message, Session, Status, status_get_phrase } from '@gi-types/soup3';
import { parse } from 'fast-xml-parser';

const debug = logger('extension-utils');
Expand Down Expand Up @@ -138,70 +128,43 @@ export const removeExtension = (extensionId: string): void => {
debug(`removed extension ${extensionId}`);
};

export const extractExtensionArchive = (bytes: ByteArray, dir: File, callback: any) => {
const extractExtensionArchive = async (bytes, dir) => {
if (!dir.query_exists(null)) {
dir.make_directory_with_parents(null);
}

const [file, stream] = File.new_tmp('XXXXXX.shell-extension.zip');
await stream.output_stream.write_bytes_async(bytes, PRIORITY_DEFAULT, null);
stream.close_async(PRIORITY_DEFAULT, null);

stream.output_stream.write_bytes(bytes as any, null);
stream.close(null);
const [success, pid] = spawn_async(
null,
['unzip', '-uod', `${dir.get_path()}`, '--', `${file.get_path()}`],
null,
SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
null,
);

if (!success) {
throw new Error('failed to extract extension');
}
if (pid) {
child_watch_add(PRIORITY_DEFAULT, pid, (o, status) => {
spawn_close_pid(pid);

if (status != 0) {
throw new Error('failed to extract extension');
} else {
callback();
}
});
}
const unzip = Subprocess.new(['unzip', '-uod', dir.get_path(), '--', file.get_path()], SubprocessFlags.NONE);
await unzip.wait_check_async(null);
};

export const installExtension = async (extensionId: string): Promise<void> => {
return new Promise((resolve) => {
const params = { shell_version: imports.misc.config.PACKAGE_VERSION };
const soupUri = URI.new(`https://extensions.gnome.org/download-extension/${extensionId}.shell-extension.zip`);
soupUri.set_query(form_encode_hash(params));
const params = { shell_version: imports.misc.config.PACKAGE_VERSION };
const message = Message.new_from_encoded_form(
'GET',
`https://extensions.gnome.org/download-extension/${extensionId}.shell-extension.zip`,
form_encode_hash(params),
);

const message = Message.new_from_uri('GET', soupUri);
const dir = File.new_for_path(build_filenamev([get_user_data_dir(), 'gnome-shell', 'extensions', extensionId]));

const dir = File.new_for_path(build_filenamev([get_user_data_dir(), 'gnome-shell', 'extensions', extensionId]));
try {
const bytes = await new Session().send_and_read_async(message, PRIORITY_DEFAULT, null);
const { statusCode } = message;
const phrase = status_get_phrase(statusCode);
if (statusCode !== Status.OK) throw new Error(`Unexpected response: ${phrase}`);

try {
const httpSession = new Session();
httpSession.queue_message(message, () => {
const { statusCode } = message;
const phrase = status_get_phrase(statusCode);
if (statusCode !== Status.OK) {
throw new Error(`Unexpected response: ${phrase}`);
}
const bytes = message.response_body.flatten().get_as_bytes();
extractExtensionArchive(bytes as any, dir, () => {
const extension = getExtensionManager().createExtensionObject(extensionId, dir, ExtensionType.PER_USER);
getExtensionManager().loadExtension(extension);
if (!getExtensionManager().enableExtension(extensionId)) {
throw new Error(`Cannot enable ${extensionId}`);
}
resolve();
});
});
} catch (e) {
debug(`error occurred during installation of ${extensionId}. Error: ${e}`);
resolve();
await extractExtensionArchive(bytes, dir);

const extension = getExtensionManager().createExtensionObject(extensionId, dir, ExtensionType.PER_USER);
getExtensionManager().loadExtension(extension);
if (!getExtensionManager().enableExtension(extensionId)) {
throw new Error(`Cannot enable ${extensionId}`);
}
});
} catch (e) {
debug(`error occurred during installation of ${extensionId}. Error: ${e}`);
}
};
2 changes: 1 addition & 1 deletion src/shell/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export const writeDconfData = async (schemaPath: string, data: string): Promise<
debug(`cannot load settings for ${schemaPath}`);
}
file.delete(null);
ioStream.close_async(PRIORITY_DEFAULT, null, null);
ioStream.close_async(PRIORITY_DEFAULT, null);
};

export const readDconfData = async (schemaPath: string): Promise<string> => {
Expand Down
Loading

0 comments on commit ab55c43

Please sign in to comment.