code!
[http-client.git] / manager.js
blobdb1a6005dbd38201803930efbe1be8ea64d511bf
2 class Backend {
3   constructor(backendUrl) {
4     this.baseUrl = backendUrl;
5   }
7   get(path, query) {
8     return this.request('GET', path, query);
9   }
11   post(path, query) {
12     return this.request('POST', path, query);
13   }
15   request(method, path, query) {
16     return new Promise((fulfill, reject) => {
17       let xhr = new XMLHttpRequest();
18       xhr.open(method, this.buildUrl(path, query));
19       xhr.addEventListener(
20         'load', () => fulfill(JSON.parse(xhr.responseText))
21       );
22       xhr.send();
23     });
24   }
26   buildUrl(path, query) {
27     return this.baseUrl + '/' + path + this.encodeQuery(query)
28   }
30   encodeQuery(query) {
31     return query ? '?' + Object.keys(query).map((key) => {
32       return encodeURIComponent(key) + '=' +
33         encodeURIComponent(query[key]);
34     }).join('&') : '';
35   }
38 export default class {
39   constructor(backendUrl) {
40     this.listeners = [];
41     this.backend = new Backend(backendUrl);
42     // this.state = { method: 'GET', uri: 'http://en.wikipedia.org/wiki/Philosophy' };
43     this.state = {
44       request: {
45         method: 'GET', uri: 'http://localhost:3000/stuff.json'
46       }
47     };
48     this.updateInfo().then((info) => this.updateState({ connection: info }));
49   }
51   onChange(listener) {
52     this.listeners.push(listener);
53   }
55   connect() {
56     return new Promise((fulfill, request) => {
57       let connection = new HTTP.Connection()
58   }
60   send() {
61     delete this.state.response;
62     return this.backend.post('send', this.state).
63       then((response) => this.updateState({ response: response }));
64   }
66   update(changes) {
67     this.updateState(changes);
68     this.updateInfo().then((info) => this.updateState({ connection: info }));
69   }
71   updateInfo() {
72     let uri = this.parseURI(this.state.request.uri);
73     if(uri) {
74       return this.backend.get('uri-info', uri).then((info) => {
75         console.log('info', info);
76         return info;
77       });
78     } else {
79       return new Promise((f, _) => f({}));
80     }
81   }
83   updateState(values) {
84     if(typeof(values.response) === 'object') {
85       let response = values.response;
86       if(typeof(response.body) === 'string') {
87         response.body = this.castBody(
88           response.body,
89           response.headers ? response.headers['content-type'] : ''
90         );
91       }
92     }
93     this.state = this.recursiveMerge(this.state, values);
94     this.listeners.forEach((listener) => listener(this.state));
95     return this.state;
96   }
98   castBody(body, type) {
99     if(type && type.match(/^application\/json/)) {
100       return {
101         type: 'application/json',
102         data: JSON.parse(body)
103       };
104     } else {
105       return new Blob([body], { type: type });
106     }
107   }
109   loadURIInfo(uri) {
110     return this.backend.get('uri-info', uri);
111     // return new Promise((f, _) => f(uri));
112   }
114   parseURI(uri) {
115     let match = uri.match(/^([^\:]+)\:(.+)$/), parsed = {};
116     if(! match) return parsed;
117     parsed.scheme = match[1];
118     switch(parsed.scheme) {
119     case 'http':
120     case 'https':
121       {
122         match = match[2].match(/^\/\/([^\:\/]+)(?:\:(\d+)|)(.*)$/);
123         if(! match) break;
124         parsed.host = match[1];
125         parsed.port = parseInt(
126           match[2] || (parsed.scheme === 'https' ? 443 : 80)
127         );
128         parsed.path = match[3];
129         break;
130       }
131     }
132     return parsed;
133   }
135   recursiveMerge(a, b) {
136     let result = {};
137     for(let key in a) {
138       result[key] = a[key];
139     }
140     for(let key in b) {
141       if(typeof(result[key]) === 'object' &&
142          typeof(b[key]) === 'object' &&
143          ((! result[key] instanceof Array) ||
144           result[key] === null || b[key] === null)) {
145         result[key] = this.recursiveMerge(a, b);
146       } else {
147         result[key] = b[key];
148       }
149     }
150     return result;
151   }