Skip to content

Commit

Permalink
Merge branch 'sapio-lang-master'
Browse files Browse the repository at this point in the history
  • Loading branch information
georgantas committed Apr 4, 2022
2 parents 937f681 + 0dbe52f commit c8200c4
Show file tree
Hide file tree
Showing 71 changed files with 3,834 additions and 1,368 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
"plugins": ["react", "@typescript-eslint", "unused-imports"],
"rules": {
"unused-imports/no-unused-imports": "error"
}
},
"ignorePatterns": ["**/pkg/*"]
}
21 changes: 21 additions & 0 deletions config-overrides.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Refer: https://github.com/lokesh-007/wasm-react-rust
const path = require('path');
const WasmPackPlugin = require('@wasm-tool/wasm-pack-plugin');
module.exports = function override(config, env) {
config.resolve.extensions.push('.wasm');
config.module.rules.forEach((rule) => {
(rule.oneOf || []).forEach((oneOf) => {
if (oneOf.loader && oneOf.loader.indexOf('file-loader') >= 0) {
// Make file-loader ignore WASM files
oneOf.exclude.push(/\.wasm$/);
}
});
});
config.plugins = (config.plugins || []).concat([
new WasmPackPlugin({
crateDirectory: path.resolve(__dirname, './src/Miniscript'),
outDir: path.resolve(__dirname, './src/Miniscript/pkg'),
}),
]);
return config;
};
110 changes: 110 additions & 0 deletions desktop/chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import Database from 'better-sqlite3';
import * as Bitcoin from 'bitcoinjs-lib';
import * as ed from '@noble/ed25519';
import { ipcMain } from 'electron';
import { EnvelopeIn, EnvelopeOut } from '../src/common/chat_interface';
import fetch from 'node-fetch';
import { stringify } from 'another-json';

let g_chat_server: ChatServer | null = null;
export function setup_chat() {
ipcMain.handle('chat::init', async (event) => {
if (g_chat_server) return;
const privateKey = ed.utils.randomPrivateKey();
const publicKey = await ed.getPublicKey(privateKey);
g_chat_server = new ChatServer(privateKey, publicKey);
});
ipcMain.handle('chat::send', async (event, message: EnvelopeIn) => {
if (!g_chat_server) return;
return g_chat_server.send_message(message);
});
ipcMain.handle('chat::add_user', (event, name: string, key: string) => {
if (!g_chat_server) return;
return g_chat_server.add_user(name, key);
});
ipcMain.handle('chat::list_users', (event) => {
if (!g_chat_server) return;
return g_chat_server.list_users();
});
ipcMain.handle('chat::list_channels', (event) => {
if (!g_chat_server) return;
return g_chat_server.list_channels();
});
ipcMain.handle('chat::list_messages_channel', (event, channel, since) => {
if (!g_chat_server) return;
return g_chat_server.list_messages_channel(channel, since);
});
}

class ChatServer {
db: Database.Database;
insert: Database.Statement;
list_all_users: Database.Statement;
list_all_channels: Database.Statement;
list_msg_chan: Database.Statement;
my_pk: Uint8Array;
my_sk: Uint8Array;
constructor(privateKey: Uint8Array, publicKey: Uint8Array) {
this.db = new Database(
'/Users/jr/Library/Application Support/org.judica.tor-chat/chat.sqlite3',
{ readonly: false }
);
this.insert = this.db.prepare(
'INSERT INTO user (nickname, key) VALUES (@name, @key);'
);
this.list_all_users = this.db.prepare(
'SELECT nickname, key from user;'
);
this.list_all_channels = this.db.prepare(
'SELECT DISTINCT channel_id from messages;'
);
this.list_msg_chan = this.db.prepare(
`
SELECT messages.body, user.nickname, messages.received_time
FROM messages
INNER JOIN user ON messages.user = user.userid
where messages.channel_id = ? AND messages.received_time > ?;
`
);
this.my_pk = publicKey;
this.my_sk = privateKey;
}
add_user(name: string, key: string) {
this.insert.run({ name, key });
}

list_users(): [string, string][] {
let res: any[] = this.list_all_users.all();
return res;
}

list_channels(): string[] {
return this.list_all_channels.all();
}
list_messages_channel(chan: string, since: number) {
return this.list_msg_chan.all(chan, since);
}

async send_message(m: EnvelopeIn): Promise<void> {
const partial: Partial<EnvelopeOut> = m;
partial.key = Array.from(this.my_pk);
const encoded = Buffer.from(stringify(partial), 'utf-8');
// keys, messages & other inputs can be Uint8Arrays or hex strings
// Uint8Array.from([0xde, 0xad, 0xbe, 0xef]) === 'deadbeef'
const message = Uint8Array.from(encoded);

const signature = Buffer.from(
await ed.sign(message, this.my_sk)
).toString('base64');
// const isValid = await ed.verify(signature, message, publicKey);
partial.signatures = {
[Bitcoin.crypto.sha256(Buffer.from(this.my_pk)).toString('hex')]: {
'ed25519:1': signature,
},
};
await fetch('http://127.0.0.1:46789/msg', {
method: 'POST',
body: JSON.stringify(partial) + '\n',
});
}
}
4 changes: 4 additions & 0 deletions desktop/declarations.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ declare module 'await-spawn' {
): Promise<BufferList>;
export = spawn;
}

declare module 'another-json' {
declare function stringify(js: any): string;
}
115 changes: 58 additions & 57 deletions desktop/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
get_emulator_log,
kill_emulator,
sapio,
SapioWorkspace,
start_sapio_oracle,
} from './sapio';
import { readFile, writeFile } from 'fs/promises';
Expand All @@ -11,7 +12,9 @@ import { preferences, Prefs } from './settings';
import { get_bitcoin_node } from './bitcoin_rpc';
import RpcError from 'bitcoin-core-ts/dist/src/errors/rpc-error';
import path from 'path';
import { setup_chat } from './chat';
export default function (window: BrowserWindow) {
setup_chat();
ipcMain.handle('bitcoin::command', async (event, arg) => {
const node = await get_bitcoin_node();
try {
Expand Down Expand Up @@ -41,23 +44,37 @@ export default function (window: BrowserWindow) {
const contracts = await sapio.list_contracts();
return contracts;
});
ipcMain.handle('sapio::create_contract', async (event, [which, args]) => {
const result = await sapio.create_contract(which, args);
return result;
});
ipcMain.handle(
'sapio::create_contract',
async (event, workspace, [which, psbt, args]) => {
const result = await sapio.create_contract(
workspace,
which,
psbt,
args
);
return result;
}
);

ipcMain.handle('sapio::show_config', async (event) => {
return await sapio.show_config();
});

ipcMain.handle('sapio::load_wasm_plugin', (event) => {
const plugin = dialog.showOpenDialogSync({
properties: ['openFile'],
const plugins = dialog.showOpenDialogSync({
properties: ['openFile', 'multiSelections'],
filters: [{ extensions: ['wasm'], name: 'WASM' }],
});
if (plugin && plugin.length)
return sapio.load_contract_file_name(plugin[0]!);
return { err: 'No Plugin Selected' };
const errs = [];
if (!plugins || !plugins.length) return { err: 'No Plugin Selected' };
for (const plugin of plugins) {
const loaded = sapio.load_contract_file_name(plugin);
if ('err' in loaded) {
return loaded;
}
}
return { ok: null };
});

ipcMain.handle('sapio::open_contract_from_file', (event) => {
Expand All @@ -77,62 +94,46 @@ export default function (window: BrowserWindow) {
return { ok: data };
}
});
ipcMain.handle('sapio::compiled_contracts::list', (event) => {
return sapio.list_compiled_contracts();
});
ipcMain.handle('sapio::compiled_contracts::trash', (event, file_name) => {
return sapio.trash_compiled_contract(file_name);
});
ipcMain.handle(
'sapio::compiled_contracts::list',
async (event, workspace) => {
return (
await SapioWorkspace.new(workspace)
).list_compiled_contracts();
}
);
ipcMain.handle(
'sapio::compiled_contracts::trash',
async (event, workspace, file_name) => {
return (
await SapioWorkspace.new(workspace)
).trash_compiled_contract(file_name);
}
);
ipcMain.handle('sapio::psbt::finalize', (event, psbt) => {
return sapio.psbt_finalize(psbt);
});

ipcMain.handle(
'sapio::compiled_contracts::open',
async (event, file_name) => {
const data = JSON.parse(
await readFile(
path.join(
app.getPath('userData'),
'compiled_contracts',
file_name,
'bound.json'
),
{
encoding: 'utf-8',
}
)
);
const args = JSON.parse(
await readFile(
path.join(
app.getPath('userData'),
'compiled_contracts',
file_name,
'args.json'
),
{
encoding: 'utf-8',
}
)
);
const mod = await readFile(
path.join(
app.getPath('userData'),
'compiled_contracts',
file_name,
'module.json'
),
{
encoding: 'utf-8',
}
);

const name = JSON.parse(mod).module;

async (event, workspace_name, file_name) => {
const workspace = await SapioWorkspace.new(workspace_name);
const data = await workspace.read_bound_data_for(file_name);
const name = await workspace.read_module_for(file_name);
const args = await workspace.read_args_for(file_name);
return { ok: { data, name, args } };
}
);

ipcMain.handle('sapio::workspaces::init', async (event, workspace) => {
await SapioWorkspace.new(workspace);
});
ipcMain.handle('sapio::workspaces::list', async (event) => {
return await SapioWorkspace.list_all();
});
ipcMain.handle('sapio::workspaces::trash', async (event, workspace) => {
return (await SapioWorkspace.new(workspace)).trash_workspace(workspace);
});

ipcMain.handle('write_clipboard', (event, s: string) => {
clipboard.writeText(s);
});
Expand Down
3 changes: 2 additions & 1 deletion desktop/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import { custom_sapio_config } from './settings';

import { createMenu } from './createMenu';
import register_handlers from './handlers';
import { start_sapio_oracle } from './sapio';
import { SapioWorkspace, start_sapio_oracle } from './sapio';
import { register_devtools } from './devtools';
import { get_bitcoin_node } from './bitcoin_rpc';

let mainWindow: BrowserWindow | null = null;

async function createWindow() {
await get_bitcoin_node();
await SapioWorkspace.new('default');
const startUrl =
process.env.ELECTRON_START_URL ||
url.format({
Expand Down
Loading

0 comments on commit c8200c4

Please sign in to comment.