Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Adding infrastructure for handling authorization redirects.

  • Loading branch information...
commit 5b9eee681f377a945b7c60b46b8866e2183763cb 1 parent 99af635
@akoprow akoprow authored
View
2  src/calc.opa
@@ -32,7 +32,7 @@ module Calc {
{ initial_state: void,
function parse_cmd(_) {
parser {
- case ~expr : { response: <>= {expr}</>, new_state: void }
+ case ~expr : Service.respond_with(<>= {expr}</>)
}
}
}
View
110 src/dropbox.opa
@@ -48,86 +48,68 @@ Please re-run your application with: --dropbox-config option")
private redirect = "http://{Config.host}/connect/dropbox"
- private creds = UserContext.make(Dropbox.credentials {no_credentials})
-
- private function set_auth_data(data) {
- UserContext.change(function(_) { data }, creds)
- }
-
- private function get_auth_data() {
- UserContext.execute(identity, creds)
- }
-
- private function authentication_failed() {
- Log.info("Dropbox", "authentication failed")
- }
-
- function connect(data) {
- Log.info("Dropbox", "connection data: {data}")
- match (get_auth_data()) {
+ function login(executor)(raw_token) {
+ function connect(auth_data) {
+ Log.info("Dropbox", "connection data: {raw_token}")
+ authentication_failed = {no_credentials}
+ match (auth_data) {
case ~{request_secret, request_token}:
- match (DB.OAuth.connection_result(data)) {
- case {success: s}:
- if (s.token == request_token) {
- match (DB.OAuth.get_access_token(s.token, request_secret, s.verifier)) {
- case {success: s}:
- dropbox_creds = {token: s.token, secret: s.secret}
- Log.info("Dropbox", "got credentials: {dropbox_creds}")
- {authenticated: dropbox_creds} |> set_auth_data
- default:
- authentication_failed()
- }
- } else
- authentication_failed()
- default:
- authentication_failed()
+ match (DB.OAuth.connection_result(raw_token)) {
+ case {success: s}:
+ if (s.token == request_token) {
+ match (DB.OAuth.get_access_token(s.token, request_secret, s.verifier)) {
+ case {success: s}:
+ dropbox_creds = {token: s.token, secret: s.secret}
+ Log.info("Dropbox", "got credentials: {dropbox_creds}")
+ {authenticated: dropbox_creds}
+ default:
+ authentication_failed
+ }
+ } else
+ authentication_failed
+ default:
+ authentication_failed
}
default:
- authentication_failed()
+ authentication_failed
+ }
}
+ executor(connect)
}
function authenticate() {
token = DB.OAuth.get_request_token(redirect)
Log.info("Dropbox", "Obtained request token {token}")
match (token) {
- case {success: token}:
- auth_url = DB.OAuth.build_authorize_url(token.token, redirect)
- {request_secret: token.secret, request_token: token.token} |> set_auth_data
- Client.goto(auth_url)
- none
- default:
- Log.error("Dropbox", "authorization failed")
- none
+ case {success: token}:
+ auth_url = DB.OAuth.build_authorize_url(token.token, redirect)
+ auth_state = {request_secret: token.secret, request_token: token.token}
+ { response: {redirect: auth_url},
+ state_change: {new_state: auth_state}
}
+ default:
+ Service.respond_with(<>Dropbox authorization failed</>)
+ }
}
- exposed function get_creds() {
- match (get_auth_data()) {
- case {authenticated: data}: some(data)
- default:
- authenticate();
- none
+ function ls(creds) {
+ match (creds) {
+ case {authenticated: creds}:
+ files = DB.Files("dropbox", "/").metadata(DB.default_metadata_options, creds)
+ ls_xhtml = <>Files: {files}</>
+ Service.respond_with(ls_xhtml)
+ default:
+ authenticate()
}
}
- xhtml =
- WBootstrap.Button.make(
- { button:
- <span>Dropbox</>
- , callback: function(_) { ls() }
- },
- []
- )
-
- function ls() {
- match (get_creds()) {
- case {some: creds}:
- files = DB.Files("dropbox", "/").metadata(DB.default_metadata_options, creds)
- Log.info("Dropbox", "Files: {files}")
- default:
- authentication_failed()
+ Service.spec spec =
+ { initial_state: Dropbox.credentials {no_credentials},
+ function parse_cmd(creds) {
+ parser {
+ case "ls": ls(creds)
+ }
+ }
}
- }
}
View
3  src/search.opa
@@ -316,8 +316,7 @@ Please re-run your application with: --blekko-config option")
{ initial_state: void,
function parse_cmd(_) {
parser {
- case res=SearchParser.shell:
- { response: res, new_state: void }
+ case res=SearchParser.shell: Service.respond_with(res)
}
}
}
View
98 src/service.opa
@@ -2,48 +2,89 @@
// (c) MLstate, 2011, 2012
// author: Adam Koprowski
+type Service.response =
+ { xhtml outcome } or { string redirect }
+
+type Service.state_change('state) =
+ { no_change } or { 'state new_state }
+
// service response to a command
-type Service.response('t) =
- { xhtml response, 't new_state }
+type Service.outcome('state) =
+ { Service.response response, Service.state_change('state) state_change }
// specification of a single service
-type Service.spec('t) =
- { 't initial_state,
- ('t -> Parser.general_parser(Service.response('t))) parse_cmd
+type Service.spec('state) =
+ { 'state initial_state,
+ ('state -> Parser.general_parser(Service.outcome('state))) parse_cmd
}
+type Service.cmd_executor =
+ string -> {cannot_handle} or {Service.response response}
+
+type Service.fun_executor('state) =
+ ('state -> 'state) -> void
+
// implementation of a service
-abstract type Service.t =
- Cell.cell(string, {cannot_handle} or {xhtml response})
+type Service.t('state) =
+ { Service.cmd_executor cmd_executor,
+ Service.fun_executor('state) fun_executor
+ }
server module Service {
- // builds a service from its specification
- function Service.t make(Service.spec('t) spec) {
- function process_cmd(state, cmd) {
- cmd_parser = spec.parse_cmd(state)
- match (Parser.try_parse(cmd_parser, cmd)) {
- case {some: res}:
- { return: {response: res.response},
- instruction: {set: res.new_state}
- }
- default:
- { return: {cannot_handle},
- instruction: {unchanged}
+ private function execute_cmd(service, state, cmd) {
+ cmd_parser = service.spec.parse_cmd(state)
+ match (Parser.try_parse(cmd_parser, cmd)) {
+ case {some: res}:
+ instruction =
+ match (res.state_change) {
+ case {no_change}: {unchanged}
+ case {new_state: state}: {set: state}
}
+ { return: {response: res.response}, ~instruction }
+ default:
+ { return: {cannot_handle},
+ instruction: {unchanged}
}
}
- Cell.make(spec.initial_state, process_cmd)
+ }
+
+ private function execute_fun(state, fun) {
+ new_state = fun(state)
+ { return: {cannot_handle},
+ instruction: {set: new_state}
+ }
+ }
+
+ private function process_request(service, state, cmd) {
+ match (cmd) {
+ case {execute_fun: fun}: execute_fun(state, fun)
+ case {execute_cmd: cmd}: execute_cmd(service, state, cmd)
+ }
+ }
+
+ // builds a service from its specification
+ function Service.t make({Service.spec spec, ...} service) {
+ cell = Cell.make(service.spec.initial_state, process_request(service, _, _))
+ { cmd_executor: function (cmd) { Cell.call(cell, {execute_cmd: cmd}) },
+ fun_executor: function (fun) { _ = Cell.call(cell, {execute_fun: fun}); void }
+ }
+ }
+
+ function respond_with(xhtml) {
+ { state_change: {no_change},
+ response: {outcome: xhtml}
+ }
}
}
// implementation of a system (consisting of a bunch of services)
-abstract type System.t = list(Service.t)
+abstract type System.t = list(Service.cmd_executor)
server module Shell {
- function System.t build(list(Service.t) services) {
+ function System.t build(list(Service.cmd_executor) services) {
services
}
@@ -52,12 +93,15 @@ server module Shell {
match (services) {
case []:
<>Unknown command</>
- case [x | xs]:
- match (Cell.call(x, cmd)) {
- case ~{response}:
- response
+ case [service | services]:
+ match (service(cmd)) {
+ case {response: {~outcome}}:
+ outcome
+ case {response: {~redirect}}:
+ Client.goto(redirect);
+ <></>
default:
- aux(xs)
+ aux(services)
}
}
}
View
22 src/webshell.opa
@@ -8,12 +8,11 @@ import stdlib.widgets.bootstrap
WB = WBootstrap
-shell =
- Shell.build(
- [ Service.make(Calc.spec),
- Service.make(Search.spec)
- ]
- )
+calc = Service.make(Calc)
+search = Service.make(Search)
+dropbox = Service.make(DropboxConnect)
+
+shell = Shell.build([calc.cmd_executor, search.cmd_executor, dropbox.cmd_executor])
function focus(set) {
Log.warning("focus", set);
@@ -63,7 +62,7 @@ function login_box() {
}
login =
prompt = <a>You can sign in with:</>
- block(<>{prompt}{FacebookConnect.xhtml}{DropboxConnect.xhtml}</>)
+ block(<>{prompt}{FacebookConnect.xhtml}</>)
logout =
function do_logout(_) {
Login.set_current_user({guest})
@@ -110,9 +109,12 @@ function connect(connector, raw_data) {
}
dispatcher = parser {
- case "/connect/facebook?" data=(.*) : connect(FacebookConnect.login, data)
- case "/connect/dropbox?" data=(.*) : connect(DropboxConnect.connect, data)
- case .* : page()
+ case "/connect/facebook?" data=(.*) ->
+ connect(FacebookConnect.login, data)
+ case "/connect/dropbox?" data=(.*) ->
+ connect(DropboxConnect.login(dropbox.fun_executor), data)
+ case .* ->
+ page()
}
Server.start(Server.http,
Please sign in to comment.
Something went wrong with that request. Please try again.