From bd6762399bc6929ef58e36439427e2e251846025 Mon Sep 17 00:00:00 2001 From: Bart Van Der Meerssche Date: Sat, 26 Mar 2011 22:47:42 +0000 Subject: [PATCH] [api] Persistent http[s] connections allow a pure RESTful POSTing of sensor measurement data. Thx Mathias! --- server/api/flukso/priv/dispatch.conf | 1 - server/api/flukso/src/flukso.app | 1 - server/api/flukso/src/flukso.hrl | 2 + server/api/flukso/src/flukso_sensor.erl | 91 --------------------- server/api/flukso/src/flukso_sensor_xyz.erl | 44 ++++++++-- 5 files changed, 39 insertions(+), 100 deletions(-) delete mode 100644 server/api/flukso/src/flukso_sensor.erl diff --git a/server/api/flukso/priv/dispatch.conf b/server/api/flukso/priv/dispatch.conf index 4a73fc9..c56046c 100644 --- a/server/api/flukso/priv/dispatch.conf +++ b/server/api/flukso/priv/dispatch.conf @@ -1,2 +1 @@ -{["sensor"], flukso_sensor, []}. {["sensor", sensor], flukso_sensor_xyz, []}. diff --git a/server/api/flukso/src/flukso.app b/server/api/flukso/src/flukso.app index 166c852..0fe0969 100644 --- a/server/api/flukso/src/flukso.app +++ b/server/api/flukso/src/flukso.app @@ -6,7 +6,6 @@ flukso_app, flukso_sup, flukso_deps, - flukso_sensor, flukso_sensor_xyz ]}, {registered, []}, diff --git a/server/api/flukso/src/flukso.hrl b/server/api/flukso/src/flukso.hrl index f7c6804..858d8bf 100644 --- a/server/api/flukso/src/flukso.hrl +++ b/server/api/flukso/src/flukso.hrl @@ -31,6 +31,8 @@ rrdResolution, rrdFactor, token, + device, + digest, jsonpCallback}). %% checks diff --git a/server/api/flukso/src/flukso_sensor.erl b/server/api/flukso/src/flukso_sensor.erl deleted file mode 100644 index 64101f6..0000000 --- a/server/api/flukso/src/flukso_sensor.erl +++ /dev/null @@ -1,91 +0,0 @@ -%% @author Bart Van Der Meerssche -%% @copyright (C) 2009-2011 Bart Van Der Meerssche -%%% -%%% This program is free software: you can redistribute it and/or modify -%%% it under the terms of the GNU General Public License as published by -%%% the Free Software Foundation, either version 3 of the License, or -%%% (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -%%% GNU General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License -%%% along with this program. If not, see . -%%% -%% @doc Flukso API: /sensor resource specification - --module(flukso_sensor). --author('Bart Van Der Meerssche '). - --export([init/1, - allowed_methods/2, - malformed_request/2, - is_authorized/2, - process_post/2]). - --include_lib("webmachine/include/webmachine.hrl"). --include("flukso.hrl"). - -init([]) -> - {ok, undefined}. - -% debugging -%init(Config) -> -% {{trace, "/tmp"}, Config}. - -allowed_methods(ReqData, State) -> - {['POST'], ReqData, State}. - -malformed_request(ReqData, State) -> - {_Version, ValidVersion} = check_version(wrq:get_req_header("X-Version", ReqData)), - {_Device, ValidDevice} = check_device(wrq:get_req_header("X-Device", ReqData)), - {_Digest, ValidDigest} = check_digest(wrq:get_req_header("X-Digest", ReqData)), - - {case {ValidVersion, ValidDevice, ValidDigest} of - {true, true, true} -> false; - _ -> true - end, - ReqData, State}. - -is_authorized(ReqData, State) -> - {data, Result} = mysql:execute(pool, device_key, [wrq:get_req_header("X-Device", ReqData)]), - [[Key]] = mysql:get_result_rows(Result), - Data = wrq:req_body(ReqData), - <> = crypto:sha_mac(Key, Data), - Digest = list_to_binary(io_lib:format("~40.16.0b", [X])), - - {case list_to_binary(wrq:get_req_header("X-Digest", ReqData)) of - Digest -> true; - _WrongDigest -> "access refused" - end, - ReqData, State}. - -% JSON: {"measurements":{"":[[,],...,[,]], -% ..., -% "":[[,],...,[,]]}} -% -% Mochijson2: {struct,[{<<"measurements">>, {struct, [{<<"">>, [[,],...,[,]]}, -% ..., -% {<<"">>, [[,],...,[,]]}]}}]} -% -process_post(ReqData, State) -> - {struct, JsonData} = mochijson2:decode(wrq:req_body(ReqData)), - {struct, Measurements} = proplists:get_value(<<"measurements">>, JsonData), - Ids = proplists:get_keys(Measurements), - RrdResponse = [update_rrd(RrdSensor, proplists:get_value(RrdSensor, Measurements)) || RrdSensor <- Ids], - - JsonResponse = mochijson2:encode({struct, [{<<"response">>, {struct, RrdResponse}}]}), - {true , wrq:set_resp_body(JsonResponse, ReqData), State}. - -update_rrd(RrdSensor, TimeSeries) -> - Path = "var/data/base/", - RrdData = [[integer_to_list(Time), ":", integer_to_list(Counter), " "] || [Time, Counter] <- TimeSeries], - -%debugging: io:format("~s~n", [[Path, [binary_to_list(RrdSensor)|".rrd"], " ", RrdData]]), - - case erlrrd:update([Path, [binary_to_list(RrdSensor)|".rrd"], " ", RrdData]) of - {ok, _RrdResponse} -> {RrdSensor, <<"ok">>}; - {error, RrdResponse} -> {RrdSensor, list_to_binary(RrdResponse)} - end. diff --git a/server/api/flukso/src/flukso_sensor_xyz.erl b/server/api/flukso/src/flukso_sensor_xyz.erl index 00ce506..1ddd8eb 100644 --- a/server/api/flukso/src/flukso_sensor_xyz.erl +++ b/server/api/flukso/src/flukso_sensor_xyz.erl @@ -47,13 +47,17 @@ malformed_request(ReqData, State) -> end. malformed_POST(ReqData, _State) -> - {_Version, ValidVersion} = check_version(wrq:get_req_header("X-Version", ReqData), wrq:get_qs_value("version", ReqData)), + {_Version, ValidVersion} = check_version(wrq:get_req_header("X-Version", ReqData)), {RrdSensor, ValidSensor} = check_sensor(wrq:path_info(sensor, ReqData)), + {Device, ValidDevice} = check_device(wrq:get_req_header("X-Device", ReqData)), + {Digest, ValidDigest} = check_digest(wrq:get_req_header("X-Digest", ReqData)), - State = #state{rrdSensor = RrdSensor}, + State = #state{rrdSensor = RrdSensor, + device = Device, + digest = Digest}, - {case {ValidVersion, ValidSensor} of - {true, true} -> false; + {case {ValidVersion, ValidSensor, ValidDevice, ValidDigest} of + {true, true, true, true} -> false; _ -> true end, ReqData, State}. @@ -86,8 +90,18 @@ is_authorized(ReqData, State) -> 'GET' -> is_auth_GET(ReqData, State) end. -is_auth_POST(ReqData, State) -> - {true, ReqData, State}. +is_auth_POST(ReqData, #state{device = Device, digest = ClientDigest} = State) -> + {data, Result} = mysql:execute(pool, device_key, [Device]), + [[Key]] = mysql:get_result_rows(Result), + Data = wrq:req_body(ReqData), + <> = crypto:sha_mac(Key, Data), + ServerDigest = lists:flatten(io_lib:format("~40.16.0b", [X])), + + {case ServerDigest of + ClientDigest -> true; + _WrongDigest -> "access refused" + end, + ReqData, State}. is_auth_GET(ReqData, #state{rrdSensor = RrdSensor, token = Token} = State) -> {data, Result} = mysql:execute(pool, permissions, [RrdSensor, Token]), @@ -125,5 +139,21 @@ to_json(ReqData, #state{rrdSensor = RrdSensor, rrdStart = RrdStart, rrdEnd = Rrd {{halt, 404}, ReqData, State} end. +% JSON: {"measurements":[[,],...,[,]]} +% Mochijson2: {struct,[{<<"measurements">>,[[,],...,[,]]}]} process_post(ReqData, #state{rrdSensor = RrdSensor} = State) -> - {true , ReqData, State}. + Path = "var/data/base/", + + {struct, JsonData} = mochijson2:decode(wrq:req_body(ReqData)), + Measurements = proplists:get_value(<<"measurements">>, JsonData), + RrdData = [[integer_to_list(Time), ":", integer_to_list(Counter), " "] || [Time, Counter] <- Measurements], + +%debugging: io:format("~s~n", [[Path, [RrdSensor|".rrd"], " ", RrdData]]), + + case erlrrd:update([Path, [RrdSensor|".rrd"], " ", RrdData]) of + {ok, _RrdResponse} -> RrdResponse = "ok"; + {error, RrdResponse} -> true + end, + + JsonResponse = mochijson2:encode({struct, [{<<"response">>, list_to_binary(RrdResponse)}]}), + {true , wrq:set_resp_body(JsonResponse, ReqData), State}.