Skip to content

Commit

Permalink
Dynamically change installer origin when loading projects from variou…
Browse files Browse the repository at this point in the history
…s sources (#193)

* Convert 'allowedOrigins' to TypeScript

* Add 'setOrigin' workplace reducer action

* Progress

* Refactor example projects to use example name in origin

* Misc

* Use URL origin in place of editor key for 'playground:post'

* Reintroduce details for 'tag' and 'git' origins

* Keep track of 'document.referrer' and 'window.opener'

* Misc
  • Loading branch information
rvanasa authored Sep 7, 2023
1 parent b2c4a29 commit b86dd45
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 35 deletions.
7 changes: 4 additions & 3 deletions service/pool/Logs.mo
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ module {
case (?n) { canisters.put(origin, n + 1) };
}
};
public func addInstall(origin: Text) {
public func addInstall(origin: Text, referrer: ?Text) {
// TODO: keep track of `referrer`
switch (installs.get(origin)) {
case null { installs.put(origin, 1) };
case (?n) { installs.put(origin, n + 1) };
}
};
public func dump() : ([(Text, Nat)], [(Text, Nat)]) {
(canisters.entries() |> toArray<(Text, Nat)>(_),
installs.entries() |> toArray<(Text, Nat)>(_))
(toArray<(Text, Nat)>(canisters.entries()),
toArray<(Text, Nat)>(installs.entries()))
};
public func metrics() : Text {
var result = "";
Expand Down
6 changes: 3 additions & 3 deletions service/pool/Main.mo
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
await getExpiredCanisterInfo(origin);
};

type InstallConfig = { profiling: Bool; is_whitelisted: Bool; origin: Text };
type InstallConfig = { profiling: Bool; is_whitelisted: Bool; origin: Text; referrer: ?Text };
public shared ({ caller }) func installCode(info : Types.CanisterInfo, args : Types.InstallArgs, install_config : InstallConfig) : async Types.CanisterInfo {
if (install_config.origin == "") {
throw Error.reject "Please specify an origin";
Expand Down Expand Up @@ -169,7 +169,7 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
};
await IC.install_code newArgs;
stats := Logs.updateStats(stats, #install);
statsByOrigin.addInstall(install_config.origin);
statsByOrigin.addInstall(install_config.origin, install_config.referrer);
switch (pool.refresh(info, install_config.profiling)) {
case (?newInfo) {
updateTimer(newInfo);
Expand Down Expand Up @@ -335,7 +335,7 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
switch (sanitizeInputs(caller, canister_id)) {
case (#ok info) {
let args = { arg; wasm_module; mode; canister_id };
let config = { profiling = pool.profiling caller; is_whitelisted = false; origin = "spawned" };
let config = { profiling = pool.profiling caller; is_whitelisted = false; origin = "spawned"; referrer = null };
ignore await installCode(info, args, config); // inherit the profiling of the parent
};
case (#err makeMsg) throw Error.reject(makeMsg "install_code");
Expand Down
22 changes: 20 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
getActorAliases,
getDeployedCanisters,
getShareableProject,
WorkplaceReducerAction,
} from "./contexts/WorkplaceState";
import { ProjectModal } from "./components/ProjectModal";
import { DeployModal, DeploySetter } from "./components/DeployModal";
Expand Down Expand Up @@ -70,20 +71,32 @@ const hasUrlParams = !!(
urlParams.get("post")
);
async function fetchFromUrlParams(
dispatch: (WorkplaceReducerAction) => void
dispatch: (action: WorkplaceReducerAction) => void
): Promise<Record<string, string> | undefined> {
const git = urlParams.get("git");
const tag = urlParams.get("tag");
const editorKey = urlParams.get("post");
if (editorKey) {
return setupEditorIntegration(editorKey, dispatch, worker);
const result = await setupEditorIntegration(editorKey, dispatch, worker);
if (result) {
const { origin, files } = result;
await dispatch({
type: "setOrigin",
payload: { origin: `playground:post:${origin}` },
});
return files;
}
}
if (git) {
const repo = {
repo: git,
branch: urlParams.get("branch") || "main",
dir: urlParams.get("dir") || "",
};
await dispatch({
type: "setOrigin",
payload: { origin: `playground:git:${git}` },
});
return await worker.fetchGithub(repo);
}
if (tag) {
Expand Down Expand Up @@ -132,6 +145,10 @@ async function fetchFromUrlParams(
});
}
}
await dispatch({
type: "setOrigin",
payload: { origin: `playground:tag:${tag}` },
});
return files;
}
}
Expand Down Expand Up @@ -290,6 +307,7 @@ export function App() {
candid={candidCode}
initTypes={initTypes}
logger={logger}
origin={workplaceState.origin}
/>
<AppContainer candidWidth={candidWidth} consoleHeight={consoleHeight}>
<Explorer
Expand Down
17 changes: 12 additions & 5 deletions src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ export async function deploy(
mode: string,
wasm: Uint8Array,
profiling: boolean,
logger: ILoggingStore
logger: ILoggingStore,
origin: string
): Promise<CanisterInfo | undefined> {
try {
logger.log(`Deploying code...`);
Expand All @@ -126,7 +127,8 @@ export async function deploy(
args,
"install",
profiling,
logger
logger,
origin
);
} else {
if (mode !== "reinstall" && mode !== "upgrade") {
Expand All @@ -138,7 +140,8 @@ export async function deploy(
args,
mode,
profiling,
logger
logger,
origin
);
}
//updatedState.candid = candid_source;
Expand Down Expand Up @@ -175,11 +178,13 @@ async function install(
args: Uint8Array,
mode: string,
profiling: boolean,
logger: ILoggingStore
logger: ILoggingStore,
origin: string | undefined
): Promise<CanisterInfo> {
if (!canisterInfo) {
throw new Error("no canister id");
}
origin ||= "playground";
const canisterId = canisterInfo.id;
const installArgs = {
arg: [...args],
Expand All @@ -190,7 +195,8 @@ async function install(
const installConfig = {
profiling,
is_whitelisted: false,
origin: "playground",
origin,
referrer: document.referrer || (window.opener && "(opener)") || undefined,
};
const new_info = await backend.installCode(
canisterInfo,
Expand All @@ -199,6 +205,7 @@ async function install(
);
canisterInfo = new_info;
logger.log(`Code installed at canister id ${canisterInfo.id}`);
console.log("Installed with origin:", origin);
return canisterInfo;
}

Expand Down
5 changes: 4 additions & 1 deletion src/components/DeployModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ interface DeployModalProps {
candid: string;
initTypes: Array<IDL.Type>;
logger: ILoggingStore;
origin: string | undefined;
}

const MAX_CANISTERS = 3;
Expand All @@ -116,6 +117,7 @@ export function DeployModal({
candid,
initTypes,
logger,
origin,
}: DeployModalProps) {
const [canisterName, setCanisterName] = useState("");
const [inputs, setInputs] = useState<InputBox[]>([]);
Expand Down Expand Up @@ -244,7 +246,8 @@ export function DeployModal({
mode,
compileResult.wasm,
profiling,
logger
logger,
origin
);
await isDeploy(false);
if (info) {
Expand Down
20 changes: 16 additions & 4 deletions src/components/ProjectModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import { Tab, Tabs } from "./shared/Tabs";

import { ImportGitHub } from "./ImportGithub";
import { fetchExample, exampleProjects, ExampleProject } from "../examples";
import { WorkerContext } from "../contexts/WorkplaceState";
import {
WorkerContext,
WorkplaceDispatchContext,
} from "../contexts/WorkplaceState";
import iconCaretRight from "../assets/images/icon-caret-right.svg";

const ModalContainer = styled.div`
Expand Down Expand Up @@ -63,16 +66,25 @@ export function ProjectModal({
isFirstOpen,
}: ProjectModalProps) {
const worker = useContext(WorkerContext);
const dispatch = useContext(WorkplaceDispatchContext);
async function handleSelectProjectAndClose(project: ExampleProject) {
const files = await fetchExample(worker, project);
if (files) {
await importCode(files);
close();
}
await dispatch({
type: "setOrigin",
payload: { origin: `playground:example:${project.name}` },
});
}
async function emptyProject() {
await importCode({ "Main.mo": "" });
close();
await dispatch({
type: "setOrigin",
payload: { origin: "playground:new" },
});
}

const welcomeText = (
Expand Down Expand Up @@ -123,12 +135,12 @@ export function ProjectModal({
<ProjectButton onClick={emptyProject}>
New Motoko project
</ProjectButton>
{Object.entries(exampleProjects).map(([name, project]) => (
{exampleProjects.map((project) => (
<ProjectButton
key={name}
key={project.name}
onClick={() => handleSelectProjectAndClose(project)}
>
{name}
{project.name}
</ProjectButton>
))}
</SelectList>
Expand Down
17 changes: 16 additions & 1 deletion src/contexts/WorkplaceState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface WorkplaceState {
canisters: Record<string, CanisterInfo>;
selectedCanister: string | null;
packages: Record<string, PackageInfo>;
origin: string | undefined;
}
export function getActorAliases(
canisters: Record<string, CanisterInfo>
Expand Down Expand Up @@ -121,9 +122,15 @@ export type WorkplaceReducerAction =
payload: {
/** path of file that should be updated. Should correspond to a property in state.files */
canister: CanisterInfo;
do_not_select?: bool;
do_not_select?: boolean;
/** new contents of file */
};
}
| {
type: "setOrigin";
payload: {
origin: string | undefined;
};
};

function selectFirstFile(files: Record<string, string>): string | null {
Expand Down Expand Up @@ -157,6 +164,7 @@ export const workplaceReducer = {
canisters,
selectedCanister: null,
packages: {},
origin: undefined,
};
},
/** Return updated state based on an action */
Expand Down Expand Up @@ -221,6 +229,13 @@ export const workplaceReducer = {
},
};
}
case "setOrigin": {
const { origin } = action.payload;
return {
...state,
origin,
};
}
default:
// this should never be reached. If there is a type error here, add a 'case'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand Down
38 changes: 25 additions & 13 deletions src/examples.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { RepoInfo } from "./workers/file";

export interface ExampleProject {
name: string;
repo: RepoInfo;
readme?: string;
}
Expand All @@ -12,52 +13,63 @@ const example = {
const readmeURL =
"https://raw.githubusercontent.com/dfinity/examples/master/motoko";

export const exampleProjects: Record<string, ExampleProject> = {
"Hello, world": {
export const exampleProjects: ExampleProject[] = [
{
name: "Hello, world",
repo: { dir: "motoko/echo/src", ...example },
readme: `${readmeURL}/echo/README.md`,
},
Counter: {
{
name: "Counter",
repo: { dir: "motoko/counter/src", ...example },
readme: `${readmeURL}/counter/README.md`,
},
Calculator: {
{
name: "Calculator",
repo: { dir: "motoko/calc/src", ...example },
readme: `${readmeURL}/calc/README.md`,
},
"Who am I?": {
{
name: "Who am I?",
repo: { dir: "motoko/whoami/src", ...example },
readme: `${readmeURL}/whoami/README.md`,
},
"Phone Book": {
{
name: "Phone Book",
repo: { dir: "motoko/phone-book/src/phone-book", ...example },
readme: `${readmeURL}/phone-book/README.md`,
},
"Super Heroes": {
{
name: "Super Heroes",
repo: { dir: "motoko/superheroes/src/superheroes", ...example },
readme: `${readmeURL}/superheroes/README.md`,
},
"Random Maze": {
{
name: "Random Maze",
repo: { dir: "motoko/random_maze/src/random_maze", ...example },
readme: `${readmeURL}/random_maze/README.md`,
},
"Game of Life": {
{
name: "Game of Life",
repo: { dir: "motoko/life", ...example },
readme: `${readmeURL}/life/README.md`,
},
"Publisher and Subscriber": {
{
name: "Publisher and Subscriber",
repo: { dir: "motoko/pub-sub/src", ...example },
readme: `${readmeURL}/pub-sub/README.md`,
},
"Actor Classes": {
{
name: "Actor Classes",
repo: { dir: "motoko/classes/src", ...example },
readme: `${readmeURL}/classes/README.md`,
},
"Basic DAO": {
{
name: "Basic DAO",
repo: { dir: "motoko/basic_dao/src", ...example },
readme: `${readmeURL}/basic_dao/README.md`,
},
};
];

export async function fetchExample(
worker,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// please submit a PR including the URL prefix for your application.
// Read more: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#security_concerns

const ALLOWED_ORIGINS = [
const ALLOWED_ORIGINS: (string | RegExp)[] = [
/^https?:\/\/(localhost|127\.0\.0\.1)(:[0-9]+)?$/, // Localhost
"https://blocks-editor.github.io", // Blocks (visual Motoko smart contract editor)
];
Expand Down
Loading

0 comments on commit b86dd45

Please sign in to comment.