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

Simple SDNA governance #422

Merged
merged 14 commits into from
Nov 24, 2023
12 changes: 6 additions & 6 deletions cli/src/perspectives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub enum PerspectiveFunctions {
Repl { id: String },

/// Set Social DNA of given perspective with SDNA code from file
SetDna { id: String, file: String },
AddDna { id: String, name: String, file: String, dna_type: String },

/// Get all defined Subject classes
SubjectClasses { id: String },
Expand Down Expand Up @@ -117,13 +117,13 @@ pub async fn run(ad4m_client: Ad4mClient, command: Option<PerspectiveFunctions>)
if let Some(nh) = perspective.neighbourhood {
println!(
"\x1b[36mNeighbourhood Link-Language: \x1b[97m{}",
nh.link_language
nh.data.link_language
);
if nh.meta.links.is_empty() {
if nh.data.meta.links.is_empty() {
println!("\x1b[36mNeughbourhood meta: \x1b[90m<empty>");
} else {
println!("\x1b[36mNeughbourhood meta:");
for link in nh.meta.links {
for link in nh.data.meta.links {
print_link(link.into());
}
}
Expand Down Expand Up @@ -196,11 +196,11 @@ pub async fn run(ad4m_client: Ad4mClient, command: Option<PerspectiveFunctions>)
//let _ = perspectives::run_watch(cap_token, id);
repl_loop(ad4m_client.perspectives.get(id).await?).await?;
}
PerspectiveFunctions::SetDna { id, file } => {
PerspectiveFunctions::AddDna { id, file, name, dna_type} => {
let dna = std::fs::read_to_string(file.clone())
.with_context(|| anyhow!("Could not read provided SDNA file {}", file))?;
let perspective = ad4m_client.perspectives.get(id).await?;
perspective.set_dna(dna).await?;
perspective.add_dna(name, dna, dna_type).await?;
println!("SDNA set successfully");
}
PerspectiveFunctions::SubjectClasses { id } => {
Expand Down
2 changes: 1 addition & 1 deletion core/src/Ad4mClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ describe('Ad4mClient', () => {
expect(p1.uuid).toBe('00001')
expect(p2.uuid).toBe('00002')
expect(p2.sharedUrl).toBe('neighbourhood://Qm12345')
expect(p2.neighbourhood.linkLanguage).toBe("language://Qm12345")
expect(p2.neighbourhood.data.linkLanguage).toBe("language://Qm12345")
})

it('byUUID() smoke test', async () => {
Expand Down
25 changes: 14 additions & 11 deletions core/src/neighbourhood/NeighbourhoodClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,26 @@ export class NeighbourhoodClient {

async joinFromUrl(url: string): Promise<PerspectiveHandle> {
const { neighbourhoodJoinFromUrl } = unwrapApolloResult(await this.#apolloClient.mutate({
mutation: gql` mutation neighbourhoodJoinFromUrl($url: String!) {
mutation: gql`mutation neighbourhoodJoinFromUrl($url: String!) {
neighbourhoodJoinFromUrl(url: $url) {
uuid
name
sharedUrl
state
neighbourhood {
linkLanguage
meta {
links
{
author
timestamp
data { source, predicate, target }
proof { valid, invalid, signature, key }
}
}
data {
linkLanguage
meta {
links
{
author
timestamp
data { source, predicate, target }
proof { valid, invalid, signature, key }
}
}
}
author
}
}
}`,
Expand Down
21 changes: 12 additions & 9 deletions core/src/perspectives/PerspectiveClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,19 @@ name
sharedUrl
state
neighbourhood {
linkLanguage
meta {
links
{
author
timestamp
data { source, predicate, target }
proof { valid, invalid, signature, key }
}
data {
linkLanguage
meta {
links
{
author
timestamp
data { source, predicate, target }
proof { valid, invalid, signature, key }
}
}
}
author
}
`

Expand Down
6 changes: 3 additions & 3 deletions core/src/perspectives/PerspectiveHandle.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Field, ObjectType } from "type-graphql";
import { Neighbourhood } from "../neighbourhood/Neighbourhood";
import { NeighbourhoodExpression } from "../neighbourhood/Neighbourhood";

export enum PerspectiveState {
Private = "Private",
Expand All @@ -24,8 +24,8 @@ export class PerspectiveHandle {
@Field(type => String, {nullable: true})
sharedUrl?: string

@Field(type => Neighbourhood, {nullable: true})
neighbourhood?: Neighbourhood
@Field(type => NeighbourhoodExpression, {nullable: true})
neighbourhood?: NeighbourhoodExpression

constructor(uuid?: string, name?: string, state?: PerspectiveState) {
this.uuid = uuid
Expand Down
78 changes: 37 additions & 41 deletions core/src/perspectives/PerspectiveProxy.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { LinkCallback, PerspectiveClient, SyncStateChangeCallback } from "./PerspectiveClient";
import { Link, LinkExpression, LinkExpressionInput, LinkExpressionMutations, LinkMutations } from "../links/Links";
import { LinkQuery } from "./LinkQuery";
import { Neighbourhood } from "../neighbourhood/Neighbourhood";
import { PerspectiveHandle, PerspectiveState } from './PerspectiveHandle'
import { Perspective } from "./Perspective";
import { Literal } from "../Literal";
import { Subject } from "../subject/Subject";
import { ExpressionRendered } from "../expression/Expression";
import { collectionAdderToName, collectionRemoverToName, collectionSetterToName } from "../subject/util";
import { NeighbourhoodProxy } from "../neighbourhood/NeighbourhoodProxy";
import { NeighbourhoodExpression } from "../neighbourhood/Neighbourhood";

type PerspectiveListenerTypes = "link-added" | "link-removed" | "link-updated"

Expand Down Expand Up @@ -113,7 +113,7 @@ export class PerspectiveProxy {
}

/** If the perspective is shared as a Neighbourhood, this is the Neighbourhood Expression */
get neighbourhood(): Neighbourhood|void {
get neighbourhood(): NeighbourhoodExpression|void {
return this.#handle.neighbourhood
}

Expand Down Expand Up @@ -320,36 +320,49 @@ export class PerspectiveProxy {
await this.executeAction(action, exprAddr, undefined)
}

/** Set the perspective's Social DNA code to the given string.
* This will replace all previous SDNA code elements with the new one.
*/
async setSdna(sdnaCode: string) {
await this.setSingleTarget(new Link({
source: "ad4m://self",
predicate: "ad4m://has_zome",
target: Literal.from(sdnaCode).toUrl()
}), 'shared')
}

fayeed marked this conversation as resolved.
Show resolved Hide resolved
/** Returns the perspective's Social DNA code
* This will return all SDNA code elements in an array.
*/
async getSdna(): Promise<string[]> {
let links = await this.get(new LinkQuery({
source: "ad4m://self",
predicate: "ad4m://has_zome"
predicate: "ad4m://sdna"
}))

return links.map(link => link.data.target).map(t => Literal.fromUrl(t).get())
}

/** Adds the given Social DNA code to the perspective's SDNA code */
async addSdna(sdnaCode: string) {
await this.add(new Link({
async addSdna(name: string, sdnaCode: string, type: "subject_class" | "flow" | "custom") {
let predicate = "ad4m://has_custom_sdna";

if (type === 'subject_class') predicate = "ad4m://has_subject_class"
else if (type === 'flow') predicate = "ad4m://has_flow"

const literalName = Literal.from(name).toUrl();

const links = await this.get(new LinkQuery({
source: "ad4m://self",
predicate: "ad4m://has_zome",
predicate,
target: literalName
}))

const sdnaLinks: any[] = []

if (links.length === 0) {
sdnaLinks.push(new Link({
source: "ad4m://self",
predicate,
target: literalName
}));
}

sdnaLinks.push(new Link({
source: literalName,
predicate: "ad4m://sdna",
target: Literal.from(sdnaCode).toUrl()
}))

await this.addLinks(sdnaLinks);
}

/** Returns all the Subject classes defined in this perspectives SDNA */
Expand Down Expand Up @@ -580,32 +593,15 @@ export class PerspectiveProxy {
* If there is no such class, it gets the JS class's SDNA by calling its
* static generateSDNA() function and adds it to the perspective's SDNA.
*/
async ensureSDNASubjectClass(jsClass: any, options?: { override: boolean }): Promise<void> {
async ensureSDNASubjectClass(jsClass: any): Promise<void> {
const subjectClass = await this.subjectClassesByTemplate(new jsClass)
if (!options?.override) {
if(subjectClass.length > 0) {
return
}

await this.addSdna(jsClass.generateSDNA())
} else {
let links = await this.get(new LinkQuery({
source: "ad4m://self",
predicate: "ad4m://has_zome"
}))

const link = links.find(l => {
if (l.data.target.includes(subjectClass[0])) {
return true
}

return false;
})
if(subjectClass.length > 0) {
return
}

await this.remove(link);
const { name, sdna } = jsClass.generateSDNA();

await this.addSdna(jsClass.generateSDNA())
}
fayeed marked this conversation as resolved.
Show resolved Hide resolved
await this.addSdna(name, sdna, 'subject_class');
}

getNeighbourhoodProxy(): NeighbourhoodProxy {
Expand Down
13 changes: 11 additions & 2 deletions core/src/perspectives/PerspectiveResolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Arg, Mutation, PubSub, Query, Resolver, Subscription } from "type-graphql";
import { LinkExpression, LinkExpressionInput, LinkExpressionMutations, LinkExpressionUpdated, LinkInput, LinkMutations } from "../links/Links";
import { Neighbourhood } from "../neighbourhood/Neighbourhood";
import { Neighbourhood, NeighbourhoodExpression } from "../neighbourhood/Neighbourhood";
import { LinkQuery } from "./LinkQuery";
import { Perspective } from "./Perspective";
import { LinkStatus } from "./PerspectiveProxy";
Expand Down Expand Up @@ -37,7 +37,16 @@ export default class PerspectiveResolver {
p2.name = 'test-perspective-2'
p2.uuid = '00002'
p2.sharedUrl = 'neighbourhood://Qm12345'
p2.neighbourhood = new Neighbourhood("language://Qm12345", new Perspective())
const neighbourhood = new NeighbourhoodExpression();
neighbourhood.data = new Neighbourhood("language://Qm12345", new Perspective());
neighbourhood.author = "did:ad4m:test"
neighbourhood.timestamp = Date.now()
neighbourhood.proof = {
signature: '',
key: '',
valid: true
}
p2.neighbourhood = neighbourhood
p2.state = PerspectiveState.Synced
return [p1, p2]
}
Expand Down
5 changes: 4 additions & 1 deletion core/src/subject/SDNADecorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,10 @@ export function SDNAClass(opts: SDNAClassOptions) {
sdna += "\n"
sdna += collectionsCode.join("\n")

return sdna
return {
sdna,
name: subjectName
}
}

Object.defineProperty(target, 'type', {configurable: true});
Expand Down
16 changes: 8 additions & 8 deletions executor/src/core/Ad4mCore.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Address, PublicSharing, PerspectiveHandle, Perspective, LanguageLanguageInput, LanguageExpression, LanguageMetaInput, AgentExpression, Language } from '@perspect3vism/ad4m'
import type { Address, PublicSharing, PerspectiveHandle, Perspective, LanguageLanguageInput, LanguageExpression, LanguageMetaInput, AgentExpression, Language, NeighbourhoodExpression } from '@perspect3vism/ad4m'
import { parseExprUrl, LanguageRef, Neighbourhood, PerspectiveState } from '@perspect3vism/ad4m'

import * as Config from './Config'
Expand Down Expand Up @@ -269,11 +269,13 @@ export default class Ad4mCore {
const neighbourhoodAddress = await (this.languageController.getNeighbourhoodLanguage().expressionAdapter!.putAdapter as PublicSharing).createPublic(neighbourhood)
const neighbourhoodUrl = `${Config.neighbourhoodLanguageAlias}://${neighbourhoodAddress}`

let neighbourHoodExp: NeighbourhoodExpression = await this.languageController.getPerspective(neighbourhoodAddress);

//Add shared perspective to original perpspective and then update controller
perspectiveID.sharedUrl = neighbourhoodUrl
perspectiveID.neighbourhood = neighbourhood;
perspectiveID.neighbourhood = neighbourHoodExp;
perspectiveID.state = PerspectiveState.Synced;
await this.#perspectivesController!.replace(perspectiveID, neighbourhood, false, PerspectiveState.Synced)
await this.#perspectivesController!.replace(perspectiveID, neighbourHoodExp, false, PerspectiveState.Synced)
return neighbourhoodUrl
}

Expand All @@ -287,17 +289,15 @@ export default class Ad4mCore {
if (neighbourHoodExp == null) {
throw Error(`Could not find neighbourhood with URL ${url}`);
};
console.log("Core.installNeighbourhood(): Got neighbourhood", neighbourHoodExp);
let neighbourhood: Neighbourhood = neighbourHoodExp.data;
console.log("Core.installNeighbourhood(): Got neighbourhood", JSON.stringify(neighbourHoodExp));
let neighbourhood: NeighbourhoodExpression = neighbourHoodExp;
let state = PerspectiveState.NeighbourhoodJoinInitiated;

try {
await this.languageController.languageByRef({address: neighbourhood.linkLanguage} as LanguageRef)
await this.languageController.languageByRef({address: neighbourhood.data.linkLanguage} as LanguageRef)
state = PerspectiveState.LinkLanguageInstalledButNotSynced;
} catch (e) {
state = PerspectiveState.LinkLanguageFailedToInstall;
}

console.log("Core.installNeighbourhood(): Creating perspective", url, neighbourhood, state);
return await this.#perspectivesController!.add("", url, neighbourhood, true, state);
}
Expand Down
Loading
Loading