classdef MatMust < handle %MATMUST A library to get deal with ESA webmust REST API % Follow indication in methods help. % % +++++++++++++++++++++++++++++++++++++ % Creator: Carmelo Magnafico IAPS/INAF % date: 20/06/2019 % % +++++++++++++++++++++++++++++++++++++ properties POSToptions GEToptions loginstatus url urlsub userProjects end properties (SetAccess = private) tockenfilename tockenstruct end properties (Transient) end methods function obj = MatMust(varargin) % Initialize the values obj.POSToptions = weboptions('RequestMethod', 'POST', 'ArrayFormat', 'json', 'Timeout',30, 'MediaType','application/json'); obj.GEToptions = weboptions('RequestMethod', 'GET', 'ArrayFormat', 'repeating', 'Timeout',30, 'MediaType','application/x-www-form-urlencoded'); obj.url = 'https://bepicolombo.esac.esa.int/webclient-must/'; obj.urlsub = 'mustlink/'; obj.tockenfilename = 'auth.json'; obj.loginstatus = false; %check the url if(nargin > 0) if isfield(varargin{1},'url') obj.url = varargin{1}.url; end end %check url [~,status] = urlread(obj.url); if ~status error('invalid URL') end if(MatMust_logincheck(obj)) disp('++++ MATMUST initialization ++++'); disp('++++ Access token valid. User logged in ++++'); disp('++++++++++++++++++++++++++++++++++++++++++++'); return end end function e = MatMust_logincheck(obj) f = fopen(obj.tockenfilename); e = false; % check if user is already logged in if f > 0 raw = fread(f,inf); tockenfilejson = jsondecode(char(raw)); if isfield(tockenfilejson,'token') & isfield(tockenfilejson,'expiresAt') if length(split(tockenfilejson.token,'.')) == 3 & datetime(datenum(tockenfilejson.expiresAt, 'yyyy-mm-dd HH:MM:SS'), 'ConvertFrom','datenum', 'TimeZone','utc') > datetime(datetime(now, 'ConvertFrom','datenum', 'TimeZone','local'), 'TimeZone','utc') obj.loginstatus = true; obj.tockenstruct = tockenfilejson; MatMust_getUserLinkedProjects(obj); e=true; else disp('++++ MATMUST initialization ++++'); disp('++++ invalid or exiperd access token. User not logged in yet ++++'); disp('++++ User login needed - use MatMust_login to access ++++'); disp('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'); end end else disp('++++ MATMUST initialization ++++'); disp('++++ cannot find access token. User not logged ++++'); disp('++++ User login needed - use MatMust_login to access ++++'); disp('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'); end end function t = MatMust_getTockenStatus(obj) t = obj.loginresponse; end function t = MatMust_getUserProjects(obj) if obj.loginstatus query = 'usermanagement/projects'; obj.GEToptions.HeaderFields = {'Authorization', obj.tockenstruct.token}; try response = webread([obj.url,obj.urlsub, query], obj.GEToptions); t = response ; catch ME fprintf('+++ WARNING\n%s - %s\n', ME.identifier, ME.message) end end end function t = MatMust_getUserLinkedProjects(obj, varargin) % Get the project to witch the logged in User belongs and have access to. % if 'dump' option is set a screenslash is done userInfo = MatMust_getUserInfo(obj); obj.userProjects = userInfo.projects; t = obj.userProjects; if nargin > 1 if strcmp(varargin{1},'dump') fprintf('+++++++++++++ PROJECTS LIST +++++++++++++\n'); for i = 1:numel(t) fprintf('\tname: %s\n\tdescription: %s\n\tid: %i\n', t(i).name, t(i).description, t(i).id); fprintf('+++++++++++++++++\n'); end end end end function t = MatMust_getUserInfo(obj) if obj.loginstatus query = 'usermanagement/userinfo'; obj.GEToptions.HeaderFields = {'Authorization', obj.tockenstruct.token}; try response = webread([obj.url,obj.urlsub, query], obj.GEToptions); t = response ; catch ME fprintf('+++ WARNING\n%s - %s\n', ME.identifier, ME.message) end end end function data = MatMust_getDataFromName(obj, ds, parname, dateStart, dateStop, varargin ) % data = MatMust_getDataFromName(obj, ds, parname, dateStart, dateStop, options ) % MatMust_getDataFromName get the data name parameter from the project name ds % in the time interval dateStart, dateStop. % % inputs % ------ % ds = 'string' -> name of the project i.e.'BEPICRUISE' % parname = 'string' -> a parameter name i.e. 'NCAD7EB7' % dateStart = 'yyyy-mm-dd HH:MM:SS' format date UTC time % dateStop = 'yyyy-mm-dd HH:MM:SS' format date UTC time % 'dump','plot' optional parameter to dump and plot the data % intialize data output data = []; if ~(MatMust_logincheck(obj)) return end %validate ds if isfield(obj.userProjects,'name') if ~any(strcmp({obj.userProjects.name},ds)) disp('++++ Project not in Available User List, check ds name or check you access rigth ++++'); return end end query = ['dataproviders/',ds,'/parameters/data']; obj.GEToptions.HeaderFields = {'Authorization', obj.tockenstruct.token}; if isa(parname,'cell') parname = char(join(parname,',')); end args = {'key', 'name',... 'values', (parname),... 'from', (dateStart),... 'to', (dateStop),... 'calibrate', 'false',... 'mode', 'SIMPLE'}; try data = webread([obj.url,obj.urlsub, query], args{:} ,obj.GEToptions); catch ME fprintf('+++ WARNING\n%s - %s\n', ME.identifier, ME.message) return end %refine date string to adapt MATLAB date format for i=1:numel(data) data_par = data(i).data; t = num2cell(datenum(datetime('1970-01-01', 'TimeZone','utc'))+(str2num(str2mat(data_par.date))/1000/86400)); [data(i).data.dateMAT] = deal(t{:}); clear t end if nargin > 5 if any(ismember(varargin,'dump')) fprintf('+++++++++++++ DATA RESULT LIST +++++++++++++\n'); for i=1:numel(data) data_par = data(i).data; fprintf('%s-%s: %s -> %s\n', data(i).subsystem, data(i).type, data(i).name, data(i).description ); %TODO filter for several kind of dataType 'DOUBLE', %'SIGNED_SMALL_INT', 'STRING' switch data(i).dataType case 'DOUBLE' format = '%f'; case 'SIGNED_SMALL_INT' format = '%i'; case 'STRING' format = '%s'; end format = ['%s - ',format,'\n']; for i = 1:numel(data_par) fprintf(format,datestr(data_par(i).dateMAT,'yyyy-mm-dd HH:MM:SS.FFF'), data_par(i).value ); end fprintf('\n++++++++++++++\n\n'); end fprintf('+++++++++++++++++++++++++++++++++++++++++\n'); end if any(ismember(varargin,'plot')) for i=1:numel(data) data_par = data(i).data; figure title(sprintf('%s-%s: %s -> %s\n', data(i).subsystem, data(i).type, data(i).name, data(i).description )) plot([data_par.dateMAT], [data_par.value], '-x' ); xlabel('time'); ylabel(data(i).unit); datetick('x'); grid on end end end end function t = MatMust_searchTMparFromName(obj, namequery, dataproviders, varargin) if obj.loginstatus query = 'metadata/treesearch'; obj.GEToptions.HeaderFields = {'Authorization', obj.tockenstruct.token}; if isa(dataproviders,'cell') dataproviders = char(join(dataproviders,',')); end try response = webread([obj.url,obj.urlsub, query], 'field','name','text',namequery,'dataproviders', dataproviders ,obj.GEToptions); t = response ; catch ME fprintf('+++ WARNING\n%s - %s\n', ME.identifier, ME.message) end if nargin > 3 if strcmp(varargin{1},'dump') fprintf('+++++++++++++ PARAMETERS QUERY RESULT LIST +++++++++++++\n'); found = false; for i = 1:numel(t) if numel(t(i).children) > 0 found = true; fprintf('\n\n\t+++++++++++++ %s LIST +++++++++++++\n', t(i).type); for j = 1:numel(t(i).children) par = t(i).children(j); fprintf('\ttitle: %s\n\tname: %s\n\tdescription: %s\n\tid: %s\n', par.title, par.sortingField, par.label, par.id); fprintf(' +++++++++++++++++\n'); end end end if ~found, fprintf('++++ Nothing found ++++\n'); end fprintf('++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n'); end end end end function [exit] = MatMust_login(obj, varargin ) % login % https://bepicolombo.esac.esa.int/webclient-must/mustlink/api-docs/index.html#/Authentication/login % input: % "username": "string", % "password": "string", % "maxDuration": false % output: % "token": "string", % "issuer": "string", % "subject": "string", % "issuedAt": "string", % "expiresAt": "string", % "expirationDate": "yyyy-mm-ddTHH:MM:SS.FFFZ" if ~obj.loginstatus % validation input input_validation = struct('username', 'char', 'password', 'char', 'maxDuration', 'logical' ); exit = false; if(nargin > 0) inputs = varargin{1}; e = obj.MatMust_inputvalidator(inputs, input_validation); if ~e exit = false; return else exit = true; end else exit = false; return end json_POST = inputs; query = 'auth/login/'; obj.tockenstruct = webwrite([obj.url,obj.urlsub, query],json_POST,obj.POSToptions); if isfield(obj.tockenstruct,'token') disp('+++ Succesfully logged in +++') obj.loginstatus = true; else disp('+++ Error in loggin +++') obj.loginstatus = false; end %store into a file if obj.loginstatus f = fopen(obj.tockenfilename, 'w'); text = jsonencode(obj.tockenstruct); fprintf(f,'%s',text); fclose(f); end %store the UserAvailable Projects in class Property MatMust_getUserLinkedProjects(obj); else exit = true; disp('user already loggen in') end end function exit = MatMust_inputvalidator(obj, input, validation) % For now, every validation_input field is treated as required % TODO: set add a subfield required at validataion json exit = false; val_fields = fields(validation); for i = 1:numel(val_fields) val_field = validation.(val_fields{i}); if isfield(input, val_fields{i}) if isa(input.(val_fields{i}), val_field) exit = true; else exit = false; end else exit = false; end end end end end