Skip to content

Commit

Permalink
Add new search feature to easily retrieve files by file id
Browse files Browse the repository at this point in the history
  • Loading branch information
tiusty committed Apr 21, 2023
1 parent 983c928 commit b39599b
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 8 deletions.
10 changes: 10 additions & 0 deletions package-set.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ let
, repo = "https://github.com/usergeek/canistergeek-ic-motoko"
, version = "v0.0.3"
, dependencies = ["base"] : List Text
},
{ name = "uuid"
, version = "v0.2.0"
, repo = "https://github.com/aviate-labs/uuid.mo"
, dependencies = [ "base", "io", "encoding" ]
},
{ name = "io"
, version = "v0.3.1"
, repo = "https://github.com/aviate-labs/io.mo"
, dependencies = [ "base" ]
}
] : List Package

Expand Down
48 changes: 44 additions & 4 deletions src/PersonalWebSpace_backend/main.mo
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import Random "mo:base/Random";
import RBTree "mo:base/RBTree";
import HashMap "mo:base/HashMap";
import Array "mo:base/Array";
import UUID "mo:uuid/UUID";
import Source "mo:uuid/async/SourceV4";


import Types "./Types";
Expand Down Expand Up @@ -612,7 +614,12 @@ private let maxFiles : Nat = 10; // limit to 10 files per user, adjust as needed

type UserId = Principal;
type File = Blob;
type FileInfo = (Text, File);

public type FileInfo = {
file_name : Text;
file_content : Blob;
file_id : Text;
};

public type UserRecord = {
totalSize : Nat;
Expand All @@ -621,6 +628,7 @@ public type UserRecord = {

// private var storage : {UserId; var files : [FileInfo]; var totalSize : Nat} = {};
private var storage : HashMap.HashMap<Text, UserRecord> = HashMap.HashMap(0, Text.equal, Text.hash);
private var file_search : HashMap.HashMap<Text, FileInfo> = HashMap.HashMap(0, Text.equal, Text.hash);


private func getUserTotalSize(user: UserId) : Nat {
Expand Down Expand Up @@ -663,9 +671,42 @@ public shared(msg) func upload(fileName : Text, content : File) : async Text {
return "Error: File limit reached.";
};


var found_unique_file_id : Bool = true;
var counter : Nat = 0;
var file_id = "";

// Keep searching for a unique name until one is found, the chances of collisions are really low
// but in case it happens keep looping until a file id is not found
while(found_unique_file_id)
{
// 100 is chosen arbitarily to ensure that in case of something weird happening
// there is a timeout
if (counter > 100)
{
return "Error: Failed to upload file due to not finding a unique identifier, please contact support";
};

// Technically there could be a race condition here... lets see if we can make this an atomic
// operation
let g = Source.Source();
file_id := UUID.toText(await g.new());

if (file_search.get(file_id) == null)
{
// Claim the id by putting an empty record into it
file_search.put(file_id, { file_name = "blank"; file_content = ""; file_id = "blank"});
found_unique_file_id := false;
};

counter := counter + 1;
};

// Add the new file to the user record and save it back to the
let newFiles = Array.append(userFiles, [(fileName, content)]);
let file_info = [{ file_name = fileName; file_content = content; file_id = file_id}];
let newFiles = Array.append(userFiles, file_info);
let newUserRecord = {files = newFiles; totalSize = userTotalSize + fileSize };

storage.put(Principal.toText(user), newUserRecord);

return "File successfully uploaded";
Expand All @@ -674,8 +715,7 @@ public shared(msg) func upload(fileName : Text, content : File) : async Text {
public shared(msg) func listFiles() : async [Text] {
let user = msg.caller;
let userFiles = getUserFiles(user);
return Array.map<FileInfo, Text>(userFiles, func fileInfo = fileInfo.0 );
return Array.map<FileInfo, Text>(userFiles, func fileInfo = fileInfo.file_id );
};


};
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type PersonalWebSpace =
getTokenIdsForUserDip721: (principal) -> (vec TokenId) query;
greet: (text) -> (text);
http_request: (Request) -> (Response) query;
listFiles: () -> (vec text);
logoDip721: () -> (LogoResult) query;
mintDip721: (principal, MetadataDesc) -> (MintReceipt);
nameDip721: () -> (text) query;
Expand All @@ -71,7 +72,7 @@ type PersonalWebSpace =
totalSupplyDip721: () -> (nat64) query;
transferFromDip721: (principal, principal, TokenId) -> (TxReceipt);
updateUserSpace: (UpdateMetadataValuesInput) -> (NftResult);
upload: (text, vec nat8) -> (text);
upload: (text, File) -> (text);
};
type OwnerResult =
variant {
Expand Down Expand Up @@ -160,6 +161,7 @@ type HeaderField =
text;
text;
};
type File = blob;
type ExtendedMetadataResult =
variant {
Err: ApiError;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type ExtendedMetadataResult = {
'Ok' : { 'token_id' : TokenId, 'metadata_desc' : MetadataDesc }
} |
{ 'Err' : ApiError };
export type File = Uint8Array;
export type HeaderField = [string, string];
export type InterfaceId = { 'Burn' : null } |
{ 'Mint' : null } |
Expand Down Expand Up @@ -70,6 +71,7 @@ export interface PersonalWebSpace {
'getTokenIdsForUserDip721' : ActorMethod<[Principal], BigUint64Array>,
'greet' : ActorMethod<[string], string>,
'http_request' : ActorMethod<[Request], Response>,
'listFiles' : ActorMethod<[], Array<string>>,
'logoDip721' : ActorMethod<[], LogoResult>,
'mintDip721' : ActorMethod<[Principal, MetadataDesc], MintReceipt>,
'nameDip721' : ActorMethod<[], string>,
Expand All @@ -86,7 +88,7 @@ export interface PersonalWebSpace {
TxReceipt
>,
'updateUserSpace' : ActorMethod<[UpdateMetadataValuesInput], NftResult>,
'upload' : ActorMethod<[string, Uint8Array], string>,
'upload' : ActorMethod<[string, File], string>,
}
export interface Request {
'url' : string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export const idlFactory = ({ IDL }) => {
'updatedSpaceData' : IDL.Opt(IDL.Text),
'updatedSpaceName' : IDL.Text,
});
const File = IDL.Vec(IDL.Nat8);
const PersonalWebSpace = IDL.Service({
'balanceOfDip721' : IDL.Func([IDL.Principal], [IDL.Nat64], ['query']),
'check_user_has_nft' : IDL.Func([], [IDL.Bool], ['query']),
Expand All @@ -124,6 +125,7 @@ export const idlFactory = ({ IDL }) => {
),
'greet' : IDL.Func([IDL.Text], [IDL.Text], []),
'http_request' : IDL.Func([Request], [Response], ['query']),
'listFiles' : IDL.Func([], [IDL.Vec(IDL.Text)], []),
'logoDip721' : IDL.Func([], [LogoResult], ['query']),
'mintDip721' : IDL.Func([IDL.Principal, MetadataDesc], [MintReceipt], []),
'nameDip721' : IDL.Func([], [IDL.Text], ['query']),
Expand All @@ -146,7 +148,7 @@ export const idlFactory = ({ IDL }) => {
[],
),
'updateUserSpace' : IDL.Func([UpdateMetadataValuesInput], [NftResult], []),
'upload' : IDL.Func([IDL.Text, IDL.Vec(IDL.Nat8)], [IDL.Text], []),
'upload' : IDL.Func([IDL.Text, File], [IDL.Text], []),
});
return PersonalWebSpace;
};
Expand Down
2 changes: 1 addition & 1 deletion vessel.dhall
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
dependencies = [ "base", "matchers", "accountid", "hex", "canistergeek" ],
dependencies = [ "base", "matchers", "accountid", "hex", "canistergeek", "uuid" ],
compiler = Some "0.6.28"
}

0 comments on commit b39599b

Please sign in to comment.