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

[spore-drive] Better interface for Config and Drive from ts/js package #254 #255

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions pkg/spore-drive/clients/js/gen/config/v1/config_connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ import { MethodKind } from "@bufbuild/protobuf";
export const ConfigService = {
typeName: "config.v1.ConfigService",
methods: {
/**
* @generated from rpc config.v1.ConfigService.New
*/
new: {
name: "New",
I: Empty,
O: Config,
kind: MethodKind.Unary,
},
/**
* @generated from rpc config.v1.ConfigService.Load
*/
Expand Down
25 changes: 20 additions & 5 deletions pkg/spore-drive/clients/js/src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,38 @@ import {
StringSlice,
BundleConfig,
Bundle,
SourceUpload
} from "../gen/config/v1/config_pb";

import { RPCClient } from "./ConfigClient";

async function* uploadAsyncIterator(stream: ReadableStream<Uint8Array>): AsyncIterable<SourceUpload> {
yield new SourceUpload({data:{case:"path", value:"/"}});

for await (const chunk of stream) {
yield new SourceUpload({data: {case:"chunk", value:chunk}});
}
}

// Main Config class
export class Config {
private client: RPCClient;
private source: Source;
private source?: string | ReadableStream<Uint8Array>;
private config?: ConfigMessage;

constructor(client: RPCClient, source: Source) {
this.client = client;
constructor(url: string, source?: string | ReadableStream<Uint8Array>) {
this.client = new RPCClient(url);
this.source = source;
}

async load(): Promise<void> {
this.config = await this.client.load(this.source);
async init(): Promise<void> {
if (typeof this.source === 'string') {
this.config = await this.client.load(new Source({ root: this.source, path: "/" }))
} else if (this.source instanceof ReadableStream) {
this.config = await this.client.upload(uploadAsyncIterator(this.source))
} else {
this.config = await this.client.new();
}
}

async free(): Promise<void> {
Expand Down
4 changes: 4 additions & 0 deletions pkg/spore-drive/clients/js/src/ConfigClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export class RPCClient {
this.client = createPromiseClient(ConfigService, transport);
}

async new(): Promise<Config> {
return await this.client.new(new Empty());
}

async load(source: Source): Promise<Config> {
return await this.client.load(source);
}
Expand Down
14 changes: 9 additions & 5 deletions pkg/spore-drive/clients/js/src/Drive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,20 @@ export { TauBinarySource, TauLatest, TauVersion, TauUrl, TauPath };
export class Drive {
private client: RPCClient;
private drive?: DriveMessage;
private config: Config;
private tau?: TauBinarySource;

constructor(client: RPCClient) {
this.client = client;
constructor(url: string,config: Config,tau?: TauBinarySource) {
this.client = new RPCClient(url);
this.config = config;
this.tau = tau;
}

async init(config: Config, tau?: TauBinarySource): Promise<void> {
async init(): Promise<void> {
this.drive = await this.client.new(
new DriveRequest({
config: new ConfigMessage({ id: config.id() }),
tau: tau,
config: new ConfigMessage({ id: this.config.id() }),
tau: this.tau,
})
);
}
Expand Down
15 changes: 10 additions & 5 deletions pkg/spore-drive/clients/js/src/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import * as os from "os";
import { mkdtemp, rm } from "fs/promises";
import * as unzipper from "unzipper";
import * as yaml from "js-yaml";
import { Readable } from 'stream';


export const createConfig = async (config: Config) => {
// Set Cloud Domain
Expand Down Expand Up @@ -78,7 +80,6 @@ export const createConfig = async (config: Config) => {
describe("Config Class Integration Tests", () => {
let client: RPCClient;
let config: Config;
let source: Source;
let rpcUrl: string;
let mockServerProcess: ChildProcess;
let tempDir: string;
Expand Down Expand Up @@ -117,9 +118,8 @@ describe("Config Class Integration Tests", () => {

beforeEach(async () => {
tempDir = await mkdtemp(path.join(os.tmpdir(), "cloud-")); // Create a temporary directory
source = new Source({ root: tempDir, path: "/" });
config = new Config(client, source);
await config.load();
config = new Config(rpcUrl, tempDir);
await config.init();
});

afterEach(async () => {
Expand Down Expand Up @@ -174,7 +174,7 @@ describe("Config Class Integration Tests", () => {
expect(result).toBeDefined();
});

it("should download configuration bundle and verify it", async () => {
it("should download configuration bundle and verify it locally and through upload", async () => {
await createConfig(config);

const bundleIterator = await config.Download();
Expand Down Expand Up @@ -219,6 +219,11 @@ describe("Config Class Integration Tests", () => {
const yamlObject: any = yaml.load(yamlContent.toString());

expect(yamlObject.domain.root).toBe("test.com");

const config_from_zip = new Config(rpcUrl, Readable.toWeb(fs.createReadStream(zipPath)));
await config_from_zip.init();
expect(await config_from_zip.Cloud().Domain().Root().Get()).toBe("test.com");
await config_from_zip.free()
});

it("should set and get Swarm Key", async () => {
Expand Down
20 changes: 9 additions & 11 deletions pkg/spore-drive/clients/js/src/drive.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,8 @@ export const createConfig = async (

describe("Drive Class Integration Tests", () => {
let mock_client: PromiseClient<typeof MockSSHService>;
let config_client: ConfigClient;
let drive_client: DriveClient;
let drive: Drive;
let source: Source;
let config :Config;
let rpcUrl: string;
let mockServerProcess: ChildProcess;
let tempDir: string;
Expand Down Expand Up @@ -147,8 +145,6 @@ describe("Drive Class Integration Tests", () => {
});

mock_client = createPromiseClient(MockSSHService, transport);
config_client = new ConfigClient(rpcUrl);
drive_client = new DriveClient(rpcUrl);

touchFile("/tmp/faketau")
});
Expand All @@ -162,19 +158,21 @@ describe("Drive Class Integration Tests", () => {

beforeEach(async () => {
tempDir = await mkdtemp(path.join(os.tmpdir(), "cloud-")); // Create a temporary directory
source = new Source({ root: tempDir, path: "/" });
const config = new Config(config_client, source);
drive = new Drive(drive_client);
await config.load();
config = new Config(rpcUrl, tempDir);
await config.init();
await createConfig(mock_client, config);
await drive.init(config, TauPath("/tmp/faketau"));
await config.free();

drive = new Drive(rpcUrl,config, TauPath("/tmp/faketau"));
await drive.init();
});

afterEach(async () => {
await mock_client.free(new Hostname({ name: "host1" }));
await mock_client.free(new Hostname({ name: "host2" }));

await config.free();
await drive.free();

if (tempDir) {
await rm(tempDir, { recursive: true, force: true });
}
Expand Down
9 changes: 9 additions & 0 deletions pkg/spore-drive/config/service/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ func (s *Service) Upload(ctx context.Context, stream *connect.ClientStream[pb.So
return connect.NewResponse(&pb.Config{Id: c.id}), nil
}

func (s *Service) New(context.Context, *connect.Request[pb.Empty]) (*connect.Response[pb.Config], error) {
cnf, err := s.newConfig(afero.NewMemMapFs(), "")
if err != nil {
return nil, fmt.Errorf("failed to create config: %w", err)
}

return connect.NewResponse(&pb.Config{Id: cnf.id}), nil
}

func (s *Service) Load(ctx context.Context, req *connect.Request[pb.Source]) (*connect.Response[pb.Config], error) {
root := req.Msg.GetRoot()
if root == "" {
Expand Down
1 change: 1 addition & 0 deletions pkg/spore-drive/proto/config/v1/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ message Port {

// Service
service ConfigService {
rpc New(Empty) returns (Config);
rpc Load(Source) returns (Config);
rpc Upload(stream SourceUpload) returns (Config);
rpc Download(BundleConfig) returns (stream Bundle);
Expand Down
95 changes: 50 additions & 45 deletions pkg/spore-drive/proto/gen/config/v1/config.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading