Update application code

This commit is contained in:
Pavel Murygin 2021-09-10 02:04:29 +03:00
parent fd7fadb2a9
commit 3c36e3a95b
8 changed files with 517 additions and 484 deletions

View File

@ -1,12 +1,12 @@
module App module App
import PeerId, Op, Peer from "@fluencelabs/aqua-lib/builtin.aqua" import PeerId, Op, Peer from "@fluencelabs/aqua-lib/builtin.aqua"
import AppConfig, FluentPad from "fluent-pad.aqua" import AppConfig, UserStatus, TextState from "fluent-pad.aqua"
import User, UserList, AuthResult from "user-list.aqua" import User, UserList, AuthResult from "user-list.aqua"
import EmptyServiceResult from "common.aqua" import EmptyServiceResult from "common.aqua"
import History, GetEntriesServiceResult, AddServiceResult from "history.aqua" import History, GetEntriesServiceResult, AddServiceResult from "history.aqua"
export join, getUserList, initAfterJoin, updateOnlineStatuses, leave, auth, getHistory, addEntry, FluentPad, AppConfig export join, getUserList, initAfterJoin, updateOnlineStatuses, leave, auth, getHistory, addEntry, UserStatus, TextState, AppConfig
func join(user: User) -> EmptyServiceResult: func join(user: User) -> EmptyServiceResult:
app <- AppConfig.getApp() app <- AppConfig.getApp()
@ -29,10 +29,10 @@ func initAfterJoin(me: User) -> []User:
isOnline <- Peer.is_connected(user.peer_id) isOnline <- Peer.is_connected(user.peer_id)
if isOnline: if isOnline:
on user.peer_id via user.relay_id: on user.peer_id via user.relay_id:
FluentPad.notifyUserAdded(me, true) UserStatus.notifyUserAdded(me, true)
-- else: -- else:
--` Op.identity("dontcare") --` Op.identity("dontcare")
par FluentPad.notifyUserAdded(user, isOnline) par UserStatus.notifyUserAdded(user, isOnline)
<- allUsers <- allUsers
@ -41,17 +41,17 @@ func updateOnlineStatuses():
for user <- allUsers par: for user <- allUsers par:
on user.peer_id via user.relay_id: on user.peer_id via user.relay_id:
isOnline <- Peer.is_connected(user.peer_id) isOnline <- Peer.is_connected(user.peer_id)
FluentPad.notifyOnline(user.peer_id, isOnline) UserStatus.notifyOnline(user.peer_id, isOnline)
func leave(): func leave():
app <- AppConfig.getApp() app <- AppConfig.getApp()
on app.user_list.peer_id: on app.user_list.peer_id:
UserList app.user_list.service_id UserList app.user_list.service_id
res <- UserList.leave(%init_peer_id%) res <- UserList.leave(INIT_PEER_ID)
allUsers <- getUserList() allUsers <- getUserList()
for user <- allUsers par: for user <- allUsers par:
on user.peer_id via user.relay_id: on user.peer_id via user.relay_id:
FluentPad.notifyUserRemoved(%init_peer_id%) UserStatus.notifyUserRemoved(INIT_PEER_ID)
func auth() -> AuthResult: func auth() -> AuthResult:
app <- AppConfig.getApp() app <- AppConfig.getApp()
@ -76,7 +76,7 @@ func addEntry(entry: string) -> AddServiceResult:
res <- History.add(entry, authRes.is_authenticated) res <- History.add(entry, authRes.is_authenticated)
allUsers <- getUserList() allUsers <- getUserList()
for user <- allUsers par: for user <- allUsers par:
if user.peer_id != %init_peer_id%: if user.peer_id != INIT_PEER_ID:
on user.peer_id via user.relay_id: on user.peer_id via user.relay_id:
FluentPad.notifyTextUpdate(entry, authRes.is_authenticated) TextState.notifyTextUpdate(entry, authRes.is_authenticated)
<- res <- res

View File

@ -1,4 +1,4 @@
module FluentPad declares AppConfig, FluentPad module FluentPad declares AppConfig, UserStatus, TextState
import PeerId from "@fluencelabs/aqua-lib/builtin.aqua" import PeerId from "@fluencelabs/aqua-lib/builtin.aqua"
import User from "user-list.aqua" import User from "user-list.aqua"
@ -11,10 +11,12 @@ data App:
history: ServiceInstance history: ServiceInstance
user_list: ServiceInstance user_list: ServiceInstance
service FluentPad("fluence/fluent-pad"): service UserStatus("fluence/fluent-pad/status"):
notifyOnline(userPeerId: string, isOnline: bool) notifyOnline(userPeerId: string, isOnline: bool)
notifyUserAdded(currentUser: User, isOnline: bool) notifyUserAdded(currentUser: User, isOnline: bool)
notifyUserRemoved(userPeerId: PeerId) notifyUserRemoved(userPeerId: PeerId)
service TextState("fluence/fluent-pad/text-state"):
notifyTextUpdate(changes: string, isAuthorized: bool) notifyTextUpdate(changes: string, isAuthorized: bool)
service AppConfig("fluence/get-config"): service AppConfig("fluence/get-config"):

View File

@ -14,21 +14,23 @@ import {
CallParams, CallParams,
} from '@fluencelabs/fluence/dist/internal/compilerSupport/v1'; } from '@fluencelabs/fluence/dist/internal/compilerSupport/v1';
// Services // Services
export interface FluentPadDef { export interface UserStatusDef {
notifyOnline: (userPeerId: string, isOnline: boolean, callParams: CallParams<'userPeerId' | 'isOnline'>) => void; notifyOnline: (userPeerId: string, isOnline: boolean, callParams: CallParams<'userPeerId' | 'isOnline'>) => void;
notifyTextUpdate: (changes: string, isAuthorized: boolean, callParams: CallParams<'changes' | 'isAuthorized'>) => void; notifyUserAdded: (
notifyUserAdded: (currentUser: {name:string;peer_id:string;relay_id:string}, isOnline: boolean, callParams: CallParams<'currentUser' | 'isOnline'>) => void; currentUser: { name: string; peer_id: string; relay_id: string },
notifyUserRemoved: (userPeerId: string, callParams: CallParams<'userPeerId'>) => void; isOnline: boolean,
} callParams: CallParams<'currentUser' | 'isOnline'>,
) => void;
notifyUserRemoved: (userPeerId: string, callParams: CallParams<'userPeerId'>) => void;
}
export function registerFluentPad(service: FluentPadDef): void; export function registerUserStatus(service: UserStatusDef): void;
export function registerFluentPad(serviceId: string, service: FluentPadDef): void; export function registerUserStatus(serviceId: string, service: UserStatusDef): void;
export function registerFluentPad(peer: FluencePeer, service: FluentPadDef): void; export function registerUserStatus(peer: FluencePeer, service: UserStatusDef): void;
export function registerFluentPad(peer: FluencePeer, serviceId: string, service: FluentPadDef): void; export function registerUserStatus(peer: FluencePeer, serviceId: string, service: UserStatusDef): void;
export function registerFluentPad(...args: any) { export function registerUserStatus(...args: any) {
let peer: FluencePeer; let peer: FluencePeer;
let serviceId: any; let serviceId: any;
let service: any; let service: any;
@ -42,10 +44,9 @@ export function registerFluentPad(peer: FluencePeer, serviceId: string, service:
serviceId = args[0]; serviceId = args[0];
} else if (typeof args[1] === 'string') { } else if (typeof args[1] === 'string') {
serviceId = args[1]; serviceId = args[1];
} else {
serviceId = 'fluence/fluent-pad/status';
} }
else {
serviceId = "fluence/fluent-pad"
}
if (!(args[0] instanceof FluencePeer) && typeof args[0] === 'object') { if (!(args[0] instanceof FluencePeer) && typeof args[0] === 'object') {
service = args[0]; service = args[0];
@ -61,81 +62,121 @@ export function registerFluentPad(peer: FluencePeer, serviceId: string, service:
return; return;
} }
if (req.fnName === 'notifyOnline') { if (req.fnName === 'notifyOnline') {
const callParams = { const callParams = {
...req.particleContext, ...req.particleContext,
tetraplets: { tetraplets: {
userPeerId: req.tetraplets[0],isOnline: req.tetraplets[1] userPeerId: req.tetraplets[0],
isOnline: req.tetraplets[1],
}, },
}; };
resp.retCode = ResultCodes.success; resp.retCode = ResultCodes.success;
service.notifyOnline(req.args[0], req.args[1], callParams); resp.result = {} service.notifyOnline(req.args[0], req.args[1], callParams);
resp.result = {};
} }
if (req.fnName === 'notifyTextUpdate') {
const callParams = {
...req.particleContext,
tetraplets: {
changes: req.tetraplets[0],isAuthorized: req.tetraplets[1]
},
};
resp.retCode = ResultCodes.success;
service.notifyTextUpdate(req.args[0], req.args[1], callParams); resp.result = {}
}
if (req.fnName === 'notifyUserAdded') { if (req.fnName === 'notifyUserAdded') {
const callParams = { const callParams = {
...req.particleContext, ...req.particleContext,
tetraplets: { tetraplets: {
currentUser: req.tetraplets[0],isOnline: req.tetraplets[1] currentUser: req.tetraplets[0],
isOnline: req.tetraplets[1],
}, },
}; };
resp.retCode = ResultCodes.success; resp.retCode = ResultCodes.success;
service.notifyUserAdded(req.args[0], req.args[1], callParams); resp.result = {} service.notifyUserAdded(req.args[0], req.args[1], callParams);
resp.result = {};
} }
if (req.fnName === 'notifyUserRemoved') { if (req.fnName === 'notifyUserRemoved') {
const callParams = { const callParams = {
...req.particleContext, ...req.particleContext,
tetraplets: { tetraplets: {
userPeerId: req.tetraplets[0] userPeerId: req.tetraplets[0],
}, },
}; };
resp.retCode = ResultCodes.success; resp.retCode = ResultCodes.success;
service.notifyUserRemoved(req.args[0], callParams); resp.result = {} service.notifyUserRemoved(req.args[0], callParams);
resp.result = {};
} }
next(); next();
}); });
}
export interface TextStateDef {
notifyTextUpdate: (
changes: string,
isAuthorized: boolean,
callParams: CallParams<'changes' | 'isAuthorized'>,
) => void;
}
export function registerTextState(service: TextStateDef): void;
export function registerTextState(serviceId: string, service: TextStateDef): void;
export function registerTextState(peer: FluencePeer, service: TextStateDef): void;
export function registerTextState(peer: FluencePeer, serviceId: string, service: TextStateDef): void;
export function registerTextState(...args: any) {
let peer: FluencePeer;
let serviceId: any;
let service: any;
if (args[0] instanceof FluencePeer) {
peer = args[0];
} else {
peer = FluencePeer.default;
} }
if (typeof args[0] === 'string') {
serviceId = args[0];
export interface AppConfigDef { } else if (typeof args[1] === 'string') {
getApp: (callParams: CallParams<null>) => {history:{peer_id:string;service_id:string};user_list:{peer_id:string;service_id:string}}; serviceId = args[1];
} else {
serviceId = 'fluence/fluent-pad/text-state';
} }
export function registerAppConfig(service: AppConfigDef): void; if (!(args[0] instanceof FluencePeer) && typeof args[0] === 'object') {
service = args[0];
} else if (typeof args[1] === 'object') {
service = args[1];
} else {
service = args[2];
}
peer.internals.callServiceHandler.use((req, resp, next) => {
if (req.serviceId !== serviceId) {
next();
return;
}
if (req.fnName === 'notifyTextUpdate') {
const callParams = {
...req.particleContext,
tetraplets: {
changes: req.tetraplets[0],
isAuthorized: req.tetraplets[1],
},
};
resp.retCode = ResultCodes.success;
service.notifyTextUpdate(req.args[0], req.args[1], callParams);
resp.result = {};
}
next();
});
}
export interface AppConfigDef {
getApp: (callParams: CallParams<null>) => {
history: { peer_id: string; service_id: string };
user_list: { peer_id: string; service_id: string };
};
}
export function registerAppConfig(service: AppConfigDef): void;
export function registerAppConfig(serviceId: string, service: AppConfigDef): void; export function registerAppConfig(serviceId: string, service: AppConfigDef): void;
export function registerAppConfig(peer: FluencePeer, service: AppConfigDef): void; export function registerAppConfig(peer: FluencePeer, service: AppConfigDef): void;
export function registerAppConfig(peer: FluencePeer, serviceId: string, service: AppConfigDef): void; export function registerAppConfig(peer: FluencePeer, serviceId: string, service: AppConfigDef): void;
export function registerAppConfig(...args: any) { export function registerAppConfig(...args: any) {
let peer: FluencePeer; let peer: FluencePeer;
let serviceId: any; let serviceId: any;
let service: any; let service: any;
@ -149,10 +190,9 @@ export function registerAppConfig(peer: FluencePeer, serviceId: string, service:
serviceId = args[0]; serviceId = args[0];
} else if (typeof args[1] === 'string') { } else if (typeof args[1] === 'string') {
serviceId = args[1]; serviceId = args[1];
} else {
serviceId = 'fluence/get-config';
} }
else {
serviceId = "fluence/get-config"
}
if (!(args[0] instanceof FluencePeer) && typeof args[0] === 'object') { if (!(args[0] instanceof FluencePeer) && typeof args[0] === 'object') {
service = args[0]; service = args[0];
@ -168,46 +208,46 @@ export function registerAppConfig(peer: FluencePeer, serviceId: string, service:
return; return;
} }
if (req.fnName === 'getApp') { if (req.fnName === 'getApp') {
const callParams = { const callParams = {
...req.particleContext, ...req.particleContext,
tetraplets: { tetraplets: {},
},
}; };
resp.retCode = ResultCodes.success; resp.retCode = ResultCodes.success;
resp.result = service.getApp(callParams) resp.result = service.getApp(callParams);
} }
next(); next();
}); });
} }
// Functions // Functions
export function addEntry(entry: string, config?: {ttl?: number}) : Promise<{entry_id:number;err_msg:string;ret_code:number}>; export function addEntry(
export function addEntry(peer: FluencePeer, entry: string, config?: {ttl?: number}) : Promise<{entry_id:number;err_msg:string;ret_code:number}>; entry: string,
export function addEntry(...args: any) { config?: { ttl?: number },
): Promise<{ entry_id: number; err_msg: string; ret_code: number }>;
export function addEntry(
peer: FluencePeer,
entry: string,
config?: { ttl?: number },
): Promise<{ entry_id: number; err_msg: string; ret_code: number }>;
export function addEntry(...args: any) {
let peer: FluencePeer; let peer: FluencePeer;
let entry: any; let entry: any;
let config: any; let config: any;
if (args[0] instanceof FluencePeer) { if (args[0] instanceof FluencePeer) {
peer = args[0]; peer = args[0];
entry = args[1]; entry = args[1];
config = args[2]; config = args[2];
} else { } else {
peer = FluencePeer.default; peer = FluencePeer.default;
entry = args[0]; entry = args[0];
config = args[1]; config = args[1];
} }
let request: RequestFlow; let request: RequestFlow;
const promise = new Promise<{entry_id:number;err_msg:string;ret_code:number}>((resolve, reject) => { const promise = new Promise<{ entry_id: number; err_msg: string; ret_code: number }>((resolve, reject) => {
const r = new RequestFlowBuilder() const r = new RequestFlowBuilder()
.disableInjections() .disableInjections()
.withRawScript( .withRawScript(
@ -286,7 +326,7 @@ config = args[1];
(seq (seq
(call user.$.relay_id! ("op" "noop") []) (call user.$.relay_id! ("op" "noop") [])
(xor (xor
(call user.$.peer_id! ("fluence/fluent-pad" "notifyTextUpdate") [entry res0.$.is_authenticated!]) (call user.$.peer_id! ("fluence/fluent-pad/text-state" "notifyTextUpdate") [entry res0.$.is_authenticated!])
(seq (seq
(seq (seq
(seq (seq
@ -330,13 +370,15 @@ config = args[1];
) )
.configHandler((h) => { .configHandler((h) => {
h.on('getDataSrv', '-relay-', () => { h.on('getDataSrv', '-relay-', () => {
return peer.connectionInfo.connectedRelay ; return peer.connectionInfo.connectedRelay;
});
h.on('getDataSrv', 'entry', () => {
return entry;
}); });
h.on('getDataSrv', 'entry', () => {return entry;});
h.onEvent('callbackSrv', 'response', (args) => { h.onEvent('callbackSrv', 'response', (args) => {
const [res] = args; const [res] = args;
resolve(res); resolve(res);
}); });
h.onEvent('errorHandlingSrv', 'error', (args) => { h.onEvent('errorHandlingSrv', 'error', (args) => {
const [err] = args; const [err] = args;
@ -346,9 +388,9 @@ config = args[1];
.handleScriptError(reject) .handleScriptError(reject)
.handleTimeout(() => { .handleTimeout(() => {
reject('Request timed out for addEntry'); reject('Request timed out for addEntry');
}) });
if(config && config.ttl) { if (config && config.ttl) {
r.withTTL(config.ttl) r.withTTL(config.ttl);
} }
request = r.build(); request = r.build();
}); });
@ -356,11 +398,14 @@ config = args[1];
return promise; return promise;
} }
export function getHistory(config?: {
ttl?: number;
export function getHistory(config?: {ttl?: number}) : Promise<{entries:{body:string;id:number}[];err_msg:string;ret_code:number}>; }): Promise<{ entries: { body: string; id: number }[]; err_msg: string; ret_code: number }>;
export function getHistory(peer: FluencePeer, config?: {ttl?: number}) : Promise<{entries:{body:string;id:number}[];err_msg:string;ret_code:number}>; export function getHistory(
export function getHistory(...args: any) { peer: FluencePeer,
config?: { ttl?: number },
): Promise<{ entries: { body: string; id: number }[]; err_msg: string; ret_code: number }>;
export function getHistory(...args: any) {
let peer: FluencePeer; let peer: FluencePeer;
let config: any; let config: any;
@ -373,7 +418,8 @@ config = args[1];
} }
let request: RequestFlow; let request: RequestFlow;
const promise = new Promise<{entries:{body:string;id:number}[];err_msg:string;ret_code:number}>((resolve, reject) => { const promise = new Promise<{ entries: { body: string; id: number }[]; err_msg: string; ret_code: number }>(
(resolve, reject) => {
const r = new RequestFlowBuilder() const r = new RequestFlowBuilder()
.disableInjections() .disableInjections()
.withRawScript( .withRawScript(
@ -429,13 +475,13 @@ config = args[1];
) )
.configHandler((h) => { .configHandler((h) => {
h.on('getDataSrv', '-relay-', () => { h.on('getDataSrv', '-relay-', () => {
return peer.connectionInfo.connectedRelay ; return peer.connectionInfo.connectedRelay;
}); });
h.onEvent('callbackSrv', 'response', (args) => { h.onEvent('callbackSrv', 'response', (args) => {
const [res] = args; const [res] = args;
resolve(res); resolve(res);
}); });
h.onEvent('errorHandlingSrv', 'error', (args) => { h.onEvent('errorHandlingSrv', 'error', (args) => {
const [err] = args; const [err] = args;
@ -445,36 +491,42 @@ config = args[1];
.handleScriptError(reject) .handleScriptError(reject)
.handleTimeout(() => { .handleTimeout(() => {
reject('Request timed out for getHistory'); reject('Request timed out for getHistory');
}) });
if(config && config.ttl) { if (config && config.ttl) {
r.withTTL(config.ttl) r.withTTL(config.ttl);
} }
request = r.build(); request = r.build();
}); },
);
peer.internals.initiateFlow(request!); peer.internals.initiateFlow(request!);
return promise; return promise;
} }
export function initAfterJoin(
me: { name: string; peer_id: string; relay_id: string },
export function initAfterJoin(me: {name:string;peer_id:string;relay_id:string}, config?: {ttl?: number}) : Promise<{name:string;peer_id:string;relay_id:string}[]>; config?: { ttl?: number },
export function initAfterJoin(peer: FluencePeer, me: {name:string;peer_id:string;relay_id:string}, config?: {ttl?: number}) : Promise<{name:string;peer_id:string;relay_id:string}[]>; ): Promise<{ name: string; peer_id: string; relay_id: string }[]>;
export function initAfterJoin(...args: any) { export function initAfterJoin(
peer: FluencePeer,
me: { name: string; peer_id: string; relay_id: string },
config?: { ttl?: number },
): Promise<{ name: string; peer_id: string; relay_id: string }[]>;
export function initAfterJoin(...args: any) {
let peer: FluencePeer; let peer: FluencePeer;
let me: any; let me: any;
let config: any; let config: any;
if (args[0] instanceof FluencePeer) { if (args[0] instanceof FluencePeer) {
peer = args[0]; peer = args[0];
me = args[1]; me = args[1];
config = args[2]; config = args[2];
} else { } else {
peer = FluencePeer.default; peer = FluencePeer.default;
me = args[0]; me = args[0];
config = args[1]; config = args[1];
} }
let request: RequestFlow; let request: RequestFlow;
const promise = new Promise<{name:string;peer_id:string;relay_id:string}[]>((resolve, reject) => { const promise = new Promise<{ name: string; peer_id: string; relay_id: string }[]>((resolve, reject) => {
const r = new RequestFlowBuilder() const r = new RequestFlowBuilder()
.disableInjections() .disableInjections()
.withRawScript( .withRawScript(
@ -530,7 +582,7 @@ config = args[1];
(match isOnline true (match isOnline true
(xor (xor
(xor (xor
(call user.$.peer_id! ("fluence/fluent-pad" "notifyUserAdded") [me true]) (call user.$.peer_id! ("fluence/fluent-pad/status" "notifyUserAdded") [me true])
(seq (seq
(seq (seq
(seq (seq
@ -556,7 +608,7 @@ config = args[1];
) )
(seq (seq
(call -relay- ("op" "noop") []) (call -relay- ("op" "noop") [])
(call %init_peer_id% ("fluence/fluent-pad" "notifyUserAdded") [user isOnline]) (call %init_peer_id% ("fluence/fluent-pad/status" "notifyUserAdded") [user isOnline])
) )
) )
) )
@ -579,13 +631,15 @@ config = args[1];
) )
.configHandler((h) => { .configHandler((h) => {
h.on('getDataSrv', '-relay-', () => { h.on('getDataSrv', '-relay-', () => {
return peer.connectionInfo.connectedRelay ; return peer.connectionInfo.connectedRelay;
});
h.on('getDataSrv', 'me', () => {
return me;
}); });
h.on('getDataSrv', 'me', () => {return me;});
h.onEvent('callbackSrv', 'response', (args) => { h.onEvent('callbackSrv', 'response', (args) => {
const [res] = args; const [res] = args;
resolve(res); resolve(res);
}); });
h.onEvent('errorHandlingSrv', 'error', (args) => { h.onEvent('errorHandlingSrv', 'error', (args) => {
const [err] = args; const [err] = args;
@ -595,9 +649,9 @@ config = args[1];
.handleScriptError(reject) .handleScriptError(reject)
.handleTimeout(() => { .handleTimeout(() => {
reject('Request timed out for initAfterJoin'); reject('Request timed out for initAfterJoin');
}) });
if(config && config.ttl) { if (config && config.ttl) {
r.withTTL(config.ttl) r.withTTL(config.ttl);
} }
request = r.build(); request = r.build();
}); });
@ -605,11 +659,9 @@ config = args[1];
return promise; return promise;
} }
export function updateOnlineStatuses(config?: { ttl?: number }): Promise<void>;
export function updateOnlineStatuses(peer: FluencePeer, config?: { ttl?: number }): Promise<void>;
export function updateOnlineStatuses(config?: {ttl?: number}) : Promise<void>; export function updateOnlineStatuses(...args: any) {
export function updateOnlineStatuses(peer: FluencePeer, config?: {ttl?: number}) : Promise<void>;
export function updateOnlineStatuses(...args: any) {
let peer: FluencePeer; let peer: FluencePeer;
let config: any; let config: any;
@ -679,7 +731,7 @@ config = args[1];
) )
(call -relay- ("op" "noop") []) (call -relay- ("op" "noop") [])
) )
(call %init_peer_id% ("fluence/fluent-pad" "notifyOnline") [user.$.peer_id! isOnline]) (call %init_peer_id% ("fluence/fluent-pad/status" "notifyOnline") [user.$.peer_id! isOnline])
) )
(seq (seq
(call -relay- ("op" "noop") []) (call -relay- ("op" "noop") [])
@ -695,12 +747,10 @@ config = args[1];
) )
.configHandler((h) => { .configHandler((h) => {
h.on('getDataSrv', '-relay-', () => { h.on('getDataSrv', '-relay-', () => {
return peer.connectionInfo.connectedRelay ; return peer.connectionInfo.connectedRelay;
}); });
h.onEvent('callbackSrv', 'response', (args) => { h.onEvent('callbackSrv', 'response', (args) => {});
});
h.onEvent('errorHandlingSrv', 'error', (args) => { h.onEvent('errorHandlingSrv', 'error', (args) => {
const [err] = args; const [err] = args;
@ -710,9 +760,9 @@ config = args[1];
.handleScriptError(reject) .handleScriptError(reject)
.handleTimeout(() => { .handleTimeout(() => {
reject('Request timed out for updateOnlineStatuses'); reject('Request timed out for updateOnlineStatuses');
}) });
if(config && config.ttl) { if (config && config.ttl) {
r.withTTL(config.ttl) r.withTTL(config.ttl);
} }
request = r.build(); request = r.build();
}); });
@ -720,11 +770,12 @@ config = args[1];
return Promise.race([promise, Promise.resolve()]); return Promise.race([promise, Promise.resolve()]);
} }
export function getUserList(config?: { ttl?: number }): Promise<{ name: string; peer_id: string; relay_id: string }[]>;
export function getUserList(
export function getUserList(config?: {ttl?: number}) : Promise<{name:string;peer_id:string;relay_id:string}[]>; peer: FluencePeer,
export function getUserList(peer: FluencePeer, config?: {ttl?: number}) : Promise<{name:string;peer_id:string;relay_id:string}[]>; config?: { ttl?: number },
export function getUserList(...args: any) { ): Promise<{ name: string; peer_id: string; relay_id: string }[]>;
export function getUserList(...args: any) {
let peer: FluencePeer; let peer: FluencePeer;
let config: any; let config: any;
@ -737,7 +788,7 @@ config = args[1];
} }
let request: RequestFlow; let request: RequestFlow;
const promise = new Promise<{name:string;peer_id:string;relay_id:string}[]>((resolve, reject) => { const promise = new Promise<{ name: string; peer_id: string; relay_id: string }[]>((resolve, reject) => {
const r = new RequestFlowBuilder() const r = new RequestFlowBuilder()
.disableInjections() .disableInjections()
.withRawScript( .withRawScript(
@ -778,13 +829,13 @@ config = args[1];
) )
.configHandler((h) => { .configHandler((h) => {
h.on('getDataSrv', '-relay-', () => { h.on('getDataSrv', '-relay-', () => {
return peer.connectionInfo.connectedRelay ; return peer.connectionInfo.connectedRelay;
}); });
h.onEvent('callbackSrv', 'response', (args) => { h.onEvent('callbackSrv', 'response', (args) => {
const [res] = args; const [res] = args;
resolve(res); resolve(res);
}); });
h.onEvent('errorHandlingSrv', 'error', (args) => { h.onEvent('errorHandlingSrv', 'error', (args) => {
const [err] = args; const [err] = args;
@ -794,9 +845,9 @@ config = args[1];
.handleScriptError(reject) .handleScriptError(reject)
.handleTimeout(() => { .handleTimeout(() => {
reject('Request timed out for getUserList'); reject('Request timed out for getUserList');
}) });
if(config && config.ttl) { if (config && config.ttl) {
r.withTTL(config.ttl) r.withTTL(config.ttl);
} }
request = r.build(); request = r.build();
}); });
@ -804,11 +855,9 @@ config = args[1];
return promise; return promise;
} }
export function leave(config?: { ttl?: number }): Promise<void>;
export function leave(peer: FluencePeer, config?: { ttl?: number }): Promise<void>;
export function leave(config?: {ttl?: number}) : Promise<void>; export function leave(...args: any) {
export function leave(peer: FluencePeer, config?: {ttl?: number}) : Promise<void>;
export function leave(...args: any) {
let peer: FluencePeer; let peer: FluencePeer;
let config: any; let config: any;
@ -876,7 +925,7 @@ config = args[1];
(seq (seq
(call user.$.relay_id! ("op" "noop") []) (call user.$.relay_id! ("op" "noop") [])
(xor (xor
(call user.$.peer_id! ("fluence/fluent-pad" "notifyUserRemoved") [%init_peer_id%]) (call user.$.peer_id! ("fluence/fluent-pad/status" "notifyUserRemoved") [%init_peer_id%])
(seq (seq
(seq (seq
(call user.$.relay_id! ("op" "noop") []) (call user.$.relay_id! ("op" "noop") [])
@ -900,12 +949,10 @@ config = args[1];
) )
.configHandler((h) => { .configHandler((h) => {
h.on('getDataSrv', '-relay-', () => { h.on('getDataSrv', '-relay-', () => {
return peer.connectionInfo.connectedRelay ; return peer.connectionInfo.connectedRelay;
}); });
h.onEvent('callbackSrv', 'response', (args) => { h.onEvent('callbackSrv', 'response', (args) => {});
});
h.onEvent('errorHandlingSrv', 'error', (args) => { h.onEvent('errorHandlingSrv', 'error', (args) => {
const [err] = args; const [err] = args;
@ -915,9 +962,9 @@ config = args[1];
.handleScriptError(reject) .handleScriptError(reject)
.handleTimeout(() => { .handleTimeout(() => {
reject('Request timed out for leave'); reject('Request timed out for leave');
}) });
if(config && config.ttl) { if (config && config.ttl) {
r.withTTL(config.ttl) r.withTTL(config.ttl);
} }
request = r.build(); request = r.build();
}); });
@ -925,26 +972,31 @@ config = args[1];
return Promise.race([promise, Promise.resolve()]); return Promise.race([promise, Promise.resolve()]);
} }
export function join(
user: { name: string; peer_id: string; relay_id: string },
export function join(user: {name:string;peer_id:string;relay_id:string}, config?: {ttl?: number}) : Promise<{err_msg:string;ret_code:number}>; config?: { ttl?: number },
export function join(peer: FluencePeer, user: {name:string;peer_id:string;relay_id:string}, config?: {ttl?: number}) : Promise<{err_msg:string;ret_code:number}>; ): Promise<{ err_msg: string; ret_code: number }>;
export function join(...args: any) { export function join(
peer: FluencePeer,
user: { name: string; peer_id: string; relay_id: string },
config?: { ttl?: number },
): Promise<{ err_msg: string; ret_code: number }>;
export function join(...args: any) {
let peer: FluencePeer; let peer: FluencePeer;
let user: any; let user: any;
let config: any; let config: any;
if (args[0] instanceof FluencePeer) { if (args[0] instanceof FluencePeer) {
peer = args[0]; peer = args[0];
user = args[1]; user = args[1];
config = args[2]; config = args[2];
} else { } else {
peer = FluencePeer.default; peer = FluencePeer.default;
user = args[0]; user = args[0];
config = args[1]; config = args[1];
} }
let request: RequestFlow; let request: RequestFlow;
const promise = new Promise<{err_msg:string;ret_code:number}>((resolve, reject) => { const promise = new Promise<{ err_msg: string; ret_code: number }>((resolve, reject) => {
const r = new RequestFlowBuilder() const r = new RequestFlowBuilder()
.disableInjections() .disableInjections()
.withRawScript( .withRawScript(
@ -988,13 +1040,15 @@ config = args[1];
) )
.configHandler((h) => { .configHandler((h) => {
h.on('getDataSrv', '-relay-', () => { h.on('getDataSrv', '-relay-', () => {
return peer.connectionInfo.connectedRelay ; return peer.connectionInfo.connectedRelay;
});
h.on('getDataSrv', 'user', () => {
return user;
}); });
h.on('getDataSrv', 'user', () => {return user;});
h.onEvent('callbackSrv', 'response', (args) => { h.onEvent('callbackSrv', 'response', (args) => {
const [res] = args; const [res] = args;
resolve(res); resolve(res);
}); });
h.onEvent('errorHandlingSrv', 'error', (args) => { h.onEvent('errorHandlingSrv', 'error', (args) => {
const [err] = args; const [err] = args;
@ -1004,9 +1058,9 @@ config = args[1];
.handleScriptError(reject) .handleScriptError(reject)
.handleTimeout(() => { .handleTimeout(() => {
reject('Request timed out for join'); reject('Request timed out for join');
}) });
if(config && config.ttl) { if (config && config.ttl) {
r.withTTL(config.ttl) r.withTTL(config.ttl);
} }
request = r.build(); request = r.build();
}); });
@ -1014,11 +1068,14 @@ config = args[1];
return promise; return promise;
} }
export function auth(config?: {
ttl?: number;
export function auth(config?: {ttl?: number}) : Promise<{err_msg:string;is_authenticated:boolean;ret_code:number}>; }): Promise<{ err_msg: string; is_authenticated: boolean; ret_code: number }>;
export function auth(peer: FluencePeer, config?: {ttl?: number}) : Promise<{err_msg:string;is_authenticated:boolean;ret_code:number}>; export function auth(
export function auth(...args: any) { peer: FluencePeer,
config?: { ttl?: number },
): Promise<{ err_msg: string; is_authenticated: boolean; ret_code: number }>;
export function auth(...args: any) {
let peer: FluencePeer; let peer: FluencePeer;
let config: any; let config: any;
@ -1031,7 +1088,7 @@ config = args[1];
} }
let request: RequestFlow; let request: RequestFlow;
const promise = new Promise<{err_msg:string;is_authenticated:boolean;ret_code:number}>((resolve, reject) => { const promise = new Promise<{ err_msg: string; is_authenticated: boolean; ret_code: number }>((resolve, reject) => {
const r = new RequestFlowBuilder() const r = new RequestFlowBuilder()
.disableInjections() .disableInjections()
.withRawScript( .withRawScript(
@ -1072,13 +1129,13 @@ config = args[1];
) )
.configHandler((h) => { .configHandler((h) => {
h.on('getDataSrv', '-relay-', () => { h.on('getDataSrv', '-relay-', () => {
return peer.connectionInfo.connectedRelay ; return peer.connectionInfo.connectedRelay;
}); });
h.onEvent('callbackSrv', 'response', (args) => { h.onEvent('callbackSrv', 'response', (args) => {
const [res] = args; const [res] = args;
resolve(res); resolve(res);
}); });
h.onEvent('errorHandlingSrv', 'error', (args) => { h.onEvent('errorHandlingSrv', 'error', (args) => {
const [err] = args; const [err] = args;
@ -1088,13 +1145,12 @@ config = args[1];
.handleScriptError(reject) .handleScriptError(reject)
.handleTimeout(() => { .handleTimeout(() => {
reject('Request timed out for auth'); reject('Request timed out for auth');
}) });
if(config && config.ttl) { if (config && config.ttl) {
r.withTTL(config.ttl) r.withTTL(config.ttl);
} }
request = r.build(); request = r.build();
}); });
peer.internals.initiateFlow(request!); peer.internals.initiateFlow(request!);
return promise; return promise;
} }

View File

@ -1,13 +1,6 @@
import config from 'src/app.json'; import config from 'src/app.json';
import { krasnodar } from '@fluencelabs/fluence-network-environment'; import { krasnodar } from '@fluencelabs/fluence-network-environment';
export const fluentPadServiceId = 'fluence/fluent-pad';
export const notifyOnlineFnName = 'notifyOnline';
export const notifyUserAddedFnName = 'notifyUserAdded';
export const notifyUserRemovedFnName = 'notifyUserRemoved';
export const notifyTextUpdateFnName = 'notifyTextUpdate';
export const userList = { export const userList = {
peer_id: config.services.user_list.node, peer_id: config.services.user_list.node,
service_id: config.services.user_list.id, service_id: config.services.user_list.id,
@ -23,7 +16,7 @@ export const fluentPadApp = {
history: history, history: history,
}; };
// export const relayNode = testNet[0]; // export const relayNode = krasnodar[0];
export const relayNode = { export const relayNode = {
multiaddr: '/ip4/127.0.0.1/tcp/4310/ws/p2p/12D3KooWKEprYXUXqoV5xSBeyqrWLpQLLH4PXfvVkDJtmcqmh5V3', multiaddr: '/ip4/127.0.0.1/tcp/4310/ws/p2p/12D3KooWKEprYXUXqoV5xSBeyqrWLpQLLH4PXfvVkDJtmcqmh5V3',
peerId: '12D3KooWKEprYXUXqoV5xSBeyqrWLpQLLH4PXfvVkDJtmcqmh5V3', peerId: '12D3KooWKEprYXUXqoV5xSBeyqrWLpQLLH4PXfvVkDJtmcqmh5V3',

View File

@ -7,42 +7,44 @@ import { UserList } from './UserList';
import { CollaborativeEditor } from './CollaborativeEditor'; import { CollaborativeEditor } from './CollaborativeEditor';
import { fluentPadApp, relayNode } from 'src/app/constants'; import { fluentPadApp, relayNode } from 'src/app/constants';
import { CheckResponse, withErrorHandlingAsync } from './util'; import { CheckResponse, withErrorHandlingAsync } from './util';
import { join, leave } from 'src/_aqua/app'; import { join, leave, registerAppConfig } from 'src/_aqua/app';
const createClientEx = async (relay) => {
const client = await createClient(relay);
client.aquaCallHandler.on('fluence/get-config', 'getApp', () => {
return fluentPadApp;
});
client.aquaCallHandler.on('fluence/get-config', 'get_init_peer_id', () => {
return client.selfPeerId;
});
client.aquaCallHandler.on('fluence/get-config', 'get_init_relay', () => {
return client.relayPeerId!;
});
return client;
};
const App = () => { const App = () => {
const [client, setClient] = useState<FluenceClient | null>(null); const [isConnected, setIsConnected] = useState<boolean>(false);
const [isInRoom, setIsInRoom] = useState<boolean>(false); const [isInRoom, setIsInRoom] = useState<boolean>(false);
const [nickName, setNickName] = useState(''); const [nickName, setNickName] = useState('');
const connect = async () => {
try {
await FluencePeer.default.init({ connectTo: relayNode });
setIsConnected(true);
registerAppConfig({
getApp: () => {
return fluentPadApp
},
})
}
catch (err) {
console.log('Peer initialization failed', err)
}
}
useEffect(() => { useEffect(() => {
createClientEx(relayNode) connect()
.then((client) => setClient(client))
.catch((err) => console.log('Client initialization failed', err));
}, []); }, []);
const joinRoom = async () => { const joinRoom = async () => {
if (!client) { if (!isConnected) {
return; return;
} }
await withErrorHandlingAsync(async () => { await withErrorHandlingAsync(async () => {
const res = await join(client, { const res = await join( {
peer_id: client.selfPeerId, peer_id: FluencePeer.default.connectionInfo.selfPeerId,
relay_id: client.relayPeerId!, relay_id: FluencePeer.default.connectionInfo.connectedRelay!,
name: nickName, name: nickName,
}); });
if (CheckResponse(res)) { if (CheckResponse(res)) {
@ -52,18 +54,18 @@ const App = () => {
}; };
const leaveRoom = async () => { const leaveRoom = async () => {
if (!client) { if (!isConnected) {
return; return;
} }
await withErrorHandlingAsync(async () => { await withErrorHandlingAsync(async () => {
await leave(client); await leave();
setIsInRoom(false); setIsInRoom(false);
}); });
}; };
return ( return (
<FluenceClientContext.Provider value={client}> <>
<div className="header-wrapper"> <div className="header-wrapper">
<div className="header"> <div className="header">
<div className="header-item"> <div className="header-item">
@ -75,7 +77,7 @@ const App = () => {
</div> </div>
<div className="header-item"> <div className="header-item">
Connection status: {client ? <span className="accent">connected</span> : 'disconnected'} Connection status: {isConnected ? <span className="accent">connected</span> : 'disconnected'}
</div> </div>
</div> </div>
</div> </div>
@ -105,7 +107,7 @@ const App = () => {
<input <input
type="submit" type="submit"
className="join-button" className="join-button"
disabled={isInRoom || !client || !nickName} disabled={isInRoom || !isConnected || !nickName}
value="Join" value="Join"
/> />
</form> </form>
@ -120,7 +122,7 @@ const App = () => {
)} )}
</div> </div>
</div> </div>
</FluenceClientContext.Provider> </>
); );
}; };

View File

@ -1,12 +1,9 @@
import _ from 'lodash'; import _ from 'lodash';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { PeerIdB58, subscribeToEvent } from '@fluencelabs/fluence';
import { fluentPadServiceId, notifyTextUpdateFnName } from 'src/app/constants';
import { useFluenceClient } from '../app/FluenceClientContext';
import { getUpdatedDocFromText, initDoc, SyncClient } from '../app/sync'; import { getUpdatedDocFromText, initDoc, SyncClient } from '../app/sync';
import { withErrorHandlingAsync } from './util'; import { withErrorHandlingAsync } from './util';
import { addEntry, getHistory } from 'src/aqua/app'; import { addEntry, getHistory, registerTextState } from 'src/_aqua/app';
const broadcastUpdates = _.debounce((text: string, syncClient: SyncClient) => { const broadcastUpdates = _.debounce((text: string, syncClient: SyncClient) => {
let doc = syncClient.getDoc(); let doc = syncClient.getDoc();
@ -17,7 +14,6 @@ const broadcastUpdates = _.debounce((text: string, syncClient: SyncClient) => {
}, 100); }, 100);
export const CollaborativeEditor = () => { export const CollaborativeEditor = () => {
const client = useFluenceClient()!;
const [text, setText] = useState<string | null>(null); const [text, setText] = useState<string | null>(null);
const [syncClient, setSyncClient] = useState(new SyncClient()); const [syncClient, setSyncClient] = useState(new SyncClient());
@ -28,7 +24,7 @@ export const CollaborativeEditor = () => {
syncClient.handleSendChanges = (changes: string) => { syncClient.handleSendChanges = (changes: string) => {
withErrorHandlingAsync(async () => { withErrorHandlingAsync(async () => {
const res = await addEntry(client, changes); const res = await addEntry(changes);
if (res.ret_code !== 0) { if (res.ret_code !== 0) {
throw new Error( throw new Error(
`Failed to add message to history service, code=${res.ret_code}, message=${res.err_msg}`, `Failed to add message to history service, code=${res.ret_code}, message=${res.err_msg}`,
@ -37,19 +33,19 @@ export const CollaborativeEditor = () => {
}); });
}; };
const unsub = subscribeToEvent(client, fluentPadServiceId, notifyTextUpdateFnName, (args, tetraplets) => { registerTextState({
const [changes, isAuthorized] = args as [string, boolean]; notifyTextUpdate: (changes, isAuthorized) => {
if (changes) { if (changes) {
syncClient.receiveChanges(changes); syncClient.receiveChanges(changes);
} }
}); }
})
syncClient.start(); syncClient.start();
// don't block // don't block
withErrorHandlingAsync(async () => { withErrorHandlingAsync(async () => {
const res = await getHistory(client); const res = await getHistory();
for (let e of res.entries) { for (let e of res.entries) {
syncClient.receiveChanges(e.body); syncClient.receiveChanges(e.body);
} }
@ -60,7 +56,6 @@ export const CollaborativeEditor = () => {
}); });
return () => { return () => {
unsub();
syncClient.stop(); syncClient.stop();
}; };
}, []); }, []);

View File

@ -1,14 +1,10 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import {
fluentPadServiceId,
notifyOnlineFnName,
notifyUserAddedFnName,
notifyUserRemovedFnName,
} from 'src/app/constants';
import { useFluenceClient } from '../app/FluenceClientContext';
import { PeerIdB58, subscribeToEvent } from '@fluencelabs/fluence';
import { withErrorHandlingAsync } from './util'; import { withErrorHandlingAsync } from './util';
import { initAfterJoin, updateOnlineStatuses } from 'src/aqua/app'; import { initAfterJoin, updateOnlineStatuses } from 'src/_aqua/app';
import { registerUserStatus } from 'src/_aqua/app';
import { FluencePeer, PeerIdB58 } from '@fluencelabs/fluence';
interface User { interface User {
id: PeerIdB58; id: PeerIdB58;
@ -16,16 +12,9 @@ interface User {
isOnline: boolean; isOnline: boolean;
} }
interface ApiUser {
name: string;
peer_id: string;
relay_id: string;
}
const refreshOnlineStatusTimeoutMs = 10000; const refreshOnlineStatusTimeoutMs = 10000;
export const UserList = (props: { selfName: string }) => { export const UserList = (props: { selfName: string }) => {
const client = useFluenceClient()!;
const [users, setUsers] = useState<Map<PeerIdB58, User>>(new Map()); const [users, setUsers] = useState<Map<PeerIdB58, User>>(new Map());
const updateOnlineStatus = (user, onlineStatus) => { const updateOnlineStatus = (user, onlineStatus) => {
@ -42,12 +31,15 @@ export const UserList = (props: { selfName: string }) => {
useEffect(() => { useEffect(() => {
const listRefreshTimer = setInterval(() => { const listRefreshTimer = setInterval(() => {
withErrorHandlingAsync(async () => { withErrorHandlingAsync(async () => {
// await updateOnlineStatuses(client); await updateOnlineStatuses();
}); });
}, refreshOnlineStatusTimeoutMs); }, refreshOnlineStatusTimeoutMs);
const unsub1 = subscribeToEvent(client, fluentPadServiceId, notifyUserAddedFnName, (args, _) => { registerUserStatus({
const [user, isOnline] = args as [ApiUser, boolean]; notifyOnline: (user, onlineStatus) => {
updateOnlineStatus(user, onlineStatus);
},
notifyUserAdded: (user, isOnline) => {
setUsers((prev) => { setUsers((prev) => {
const u = user; const u = user;
const result = new Map(prev); const result = new Map(prev);
@ -63,36 +55,29 @@ export const UserList = (props: { selfName: string }) => {
return result; return result;
}); });
}); },
const unsub2 = subscribeToEvent(client, fluentPadServiceId, notifyUserRemovedFnName, (args, _) => { notifyUserRemoved: (userLeft) => {
const [userLeft] = args as [PeerIdB58];
setUsers((prev) => { setUsers((prev) => {
const result = new Map(prev); const result = new Map(prev);
result.delete(userLeft); result.delete(userLeft);
return result; return result;
}); });
}); }
})
const unsub3 = subscribeToEvent(client, fluentPadServiceId, notifyOnlineFnName, (args, _) => {
const [user, onlineStatus] = args as [PeerIdB58, boolean];
updateOnlineStatus(user, onlineStatus);
});
// don't block // don't block
withErrorHandlingAsync(async () => { withErrorHandlingAsync(async () => {
await initAfterJoin(client, { await initAfterJoin({
name: props.selfName, name: props.selfName,
peer_id: client.selfPeerId, peer_id: FluencePeer.default.connectionInfo.selfPeerId,
relay_id: client.relayPeerId!, relay_id: FluencePeer.default.connectionInfo.connectedRelay!,
}); });
}); });
return () => { return () => {
clearTimeout(listRefreshTimer); clearTimeout(listRefreshTimer);
unsub1();
unsub2();
unsub3();
}; };
}, []); }, []);
@ -105,7 +90,7 @@ export const UserList = (props: { selfName: string }) => {
<ul> <ul>
{usersArray.map((x) => ( {usersArray.map((x) => (
<li key={x.id}> <li key={x.id}>
<span className={x.id === client.selfPeerId ? 'bold' : ''}>{x.name}</span> <span className={x.id === FluencePeer.default.connectionInfo.selfPeerId ? 'bold' : ''}>{x.name}</span>
<span className={x.isOnline ? 'green' : 'red'}> ({x.isOnline ? 'online' : 'offline'})</span> <span className={x.isOnline ? 'green' : 'red'}> ({x.isOnline ? 'online' : 'offline'})</span>
</li> </li>
))} ))}

0
deploy_docker.sh Normal file → Executable file
View File