295 Commits

Author SHA1 Message Date
m3o-actions
ed691ec515 Commit from m3o/m3o action 2021-11-22 12:25:01 +00:00
m3o-actions
c2fb06ae73 Commit from m3o/m3o action 2021-11-21 09:49:14 +00:00
m3o-actions
3d54b046da Commit from m3o/m3o action 2021-11-21 09:49:01 +00:00
m3o-actions
d33dbbf317 Commit from m3o/m3o action 2021-11-21 09:48:05 +00:00
m3o-actions
77a58e78bd Commit from m3o/m3o action 2021-11-19 14:29:44 +00:00
m3o-actions
c18f47ca4c Commit from m3o/m3o action 2021-11-19 12:14:30 +00:00
m3o-actions
33398d3eb8 Commit from m3o/m3o action 2021-11-19 11:58:09 +00:00
m3o-actions
bb46995e2f Commit from m3o/m3o action 2021-11-19 11:29:01 +00:00
m3o-actions
9c534ced3d Commit from m3o/m3o action 2021-11-19 11:06:58 +00:00
m3o-actions
15c55dec36 Commit from m3o/m3o action 2021-11-19 10:54:21 +00:00
m3o-actions
fb13c684fd Commit from m3o/m3o action 2021-11-18 13:50:00 +00:00
m3o-actions
65c906fbdc Commit from m3o/m3o action 2021-11-18 13:06:17 +00:00
m3o-actions
c362c676b2 Commit from m3o/m3o action 2021-11-18 13:02:12 +00:00
m3o-actions
9702ed5306 Commit from m3o/m3o action 2021-11-18 13:01:10 +00:00
m3o-actions
afe052b320 Commit from m3o/m3o action 2021-11-18 12:49:57 +00:00
Asim Aslam
a7879d3ff0 in travis test flag 2021-11-18 08:33:36 +00:00
Asim Aslam
45d3c6a791 remove broken examples 2021-11-18 08:32:29 +00:00
Asim Aslam
3760aaf9dd remove broken examples 2021-11-18 08:32:04 +00:00
m3o-actions
3953482915 Commit from m3o/m3o action 2021-11-17 22:21:48 +00:00
m3o-actions
9864b467b8 Commit from m3o/m3o action 2021-11-17 20:29:20 +00:00
m3o-actions
675871d282 Commit from m3o/m3o action 2021-11-17 20:17:39 +00:00
m3o-actions
3ac4947f91 Commit from m3o/m3o action 2021-11-17 20:15:24 +00:00
m3o-actions
3167558049 Commit from m3o/m3o action 2021-11-17 19:49:10 +00:00
m3o-actions
2958807fe2 Commit from m3o/m3o action 2021-11-17 16:59:11 +00:00
m3o-actions
8e553f6e16 Commit from m3o/m3o action 2021-11-17 16:56:17 +00:00
m3o-actions
bc769baed5 Commit from m3o/m3o action 2021-11-17 16:55:33 +00:00
m3o-actions
2ca79f5288 Commit from m3o/m3o action 2021-11-17 16:53:57 +00:00
m3o-actions
a22b8a3053 Commit from m3o/m3o action 2021-11-17 16:53:35 +00:00
m3o-actions
fd05c41d21 Commit from m3o/m3o action 2021-11-17 16:50:32 +00:00
m3o-actions
9bfc15e14a Commit from m3o/m3o action 2021-11-17 16:39:54 +00:00
m3o-actions
b522b298f3 Commit from m3o/m3o action 2021-11-17 16:29:53 +00:00
m3o-actions
14d247a66c Commit from m3o/m3o action 2021-11-17 12:37:29 +00:00
m3o-actions
ef2606dc60 Commit from m3o/m3o action 2021-11-17 12:28:02 +00:00
m3o-actions
be8f5aeae4 Commit from m3o/m3o action 2021-11-17 12:27:15 +00:00
m3o-actions
8dcea9e986 Commit from m3o/m3o action 2021-11-17 11:37:31 +00:00
m3o-actions
af0c644ac3 Commit from m3o/m3o action 2021-11-17 11:10:07 +00:00
m3o-actions
ebd60b1d5c Commit from m3o/m3o action 2021-11-17 10:49:59 +00:00
m3o-actions
38d4ff491f Commit from m3o/m3o action 2021-11-17 10:49:43 +00:00
m3o-actions
21395762be Commit from m3o/m3o action 2021-11-17 10:46:33 +00:00
m3o-actions
28a3532ecb Commit from m3o/m3o action 2021-11-17 10:43:23 +00:00
m3o-actions
7fec9491f1 Commit from m3o/m3o action 2021-11-17 10:34:05 +00:00
m3o-actions
ae8a49329f Commit from m3o/m3o action 2021-11-17 10:27:35 +00:00
m3o-actions
93af926271 Commit from m3o/m3o action 2021-11-17 10:20:05 +00:00
m3o-actions
40f0fb073d Commit from m3o/m3o action 2021-11-17 09:54:21 +00:00
m3o-actions
4c6a11492e Commit from m3o/m3o action 2021-11-17 09:06:03 +00:00
m3o-actions
e5f79370cd Commit from m3o/m3o action 2021-11-17 09:05:28 +00:00
m3o-actions
4e8f9de392 Commit from m3o/m3o action 2021-11-16 15:11:11 +00:00
m3o-actions
03b2b439e5 Commit from m3o/m3o action 2021-11-16 15:11:05 +00:00
m3o-actions
f1e6613177 Commit from m3o/m3o action 2021-11-16 14:48:52 +00:00
m3o-actions
ea7e43f6cd Commit from m3o/m3o action 2021-11-16 14:37:38 +00:00
m3o-actions
edd466a2f9 Commit from m3o/m3o action 2021-11-16 14:33:39 +00:00
m3o-actions
730ab1fa1e Commit from m3o/m3o action 2021-11-16 14:13:23 +00:00
m3o-actions
23dd049bf8 Commit from m3o/m3o action 2021-11-16 13:48:29 +00:00
m3o-actions
1947d31ee7 Commit from m3o/m3o action 2021-11-16 13:44:56 +00:00
m3o-actions
2b6719c9c6 Commit from m3o/m3o action 2021-11-16 13:40:43 +00:00
m3o-actions
00d34547f3 Commit from m3o/m3o action 2021-11-16 13:39:57 +00:00
m3o-actions
0f8436ce86 Commit from m3o/m3o action 2021-11-16 11:01:02 +00:00
m3o-actions
bb53f7cc48 Commit from m3o/m3o action 2021-11-16 10:46:34 +00:00
m3o-actions
9e5bed8e5a Commit from m3o/m3o action 2021-11-16 10:45:52 +00:00
m3o-actions
caac0f5355 Commit from m3o/m3o action 2021-11-16 10:36:24 +00:00
m3o-actions
5685e31a37 Commit from m3o/m3o action 2021-11-12 14:47:34 +00:00
m3o-actions
c43f57ce29 Commit from m3o/m3o action 2021-11-12 14:46:43 +00:00
m3o-actions
d9476960d4 Commit from m3o/m3o action 2021-11-11 23:36:13 +00:00
m3o-actions
3f583e059f Commit from m3o/m3o action 2021-11-11 23:27:10 +00:00
m3o-actions
bd1dcf3fed Commit from m3o/m3o action 2021-11-11 17:37:18 +00:00
m3o-actions
baff11e1d7 Commit from m3o/m3o action 2021-11-11 17:30:45 +00:00
m3o-actions
7c67ac14c2 Commit from m3o/m3o action 2021-11-11 17:12:21 +00:00
m3o-actions
fb8efda643 Commit from m3o/m3o action 2021-11-11 16:53:07 +00:00
m3o-actions
6fcd1d7028 Commit from m3o/m3o action 2021-11-11 16:30:48 +00:00
m3o-actions
02558a8f3f Commit from m3o/m3o action 2021-11-11 16:12:03 +00:00
m3o-actions
17f624b6a7 Commit from m3o/m3o action 2021-11-11 15:41:41 +00:00
m3o-actions
3f9d7cccf8 Commit from m3o/m3o action 2021-11-11 15:36:49 +00:00
m3o-actions
cb7f8b3403 Commit from m3o/m3o action 2021-11-11 15:27:20 +00:00
m3o-actions
072d96b1ca Commit from m3o/m3o action 2021-11-11 14:10:13 +00:00
m3o-actions
03a7225806 Commit from m3o/m3o action 2021-11-11 14:07:57 +00:00
m3o-actions
1083f55216 Commit from m3o/m3o action 2021-11-11 13:56:57 +00:00
m3o-actions
bd469033e2 Commit from m3o/m3o action 2021-11-11 13:46:49 +00:00
m3o-actions
b5f58efe8b Commit from m3o/m3o action 2021-11-11 12:45:56 +00:00
m3o-actions
018e87a593 Commit from m3o/m3o action 2021-11-11 12:43:36 +00:00
m3o-actions
07312f010e Commit from m3o/m3o action 2021-11-11 12:39:10 +00:00
m3o-actions
2321fde555 Commit from m3o/m3o action 2021-11-11 12:17:40 +00:00
m3o-actions
be676eff6c Commit from m3o/m3o action 2021-11-11 12:09:26 +00:00
m3o-actions
9dcc428a55 Commit from m3o/m3o action 2021-11-11 12:05:26 +00:00
m3o-actions
b6d8111005 Commit from m3o/m3o action 2021-11-11 12:02:51 +00:00
m3o-actions
1e54e284f6 Commit from m3o/m3o action 2021-11-11 11:59:54 +00:00
m3o-actions
d31fde4be4 Commit from m3o/m3o action 2021-11-11 11:51:18 +00:00
m3o-actions
d2adcc0208 Commit from m3o/m3o action 2021-11-11 11:19:50 +00:00
m3o-actions
956adcbced Commit from m3o/m3o action 2021-11-11 11:09:27 +00:00
m3o-actions
fab7b1892d Commit from m3o/m3o action 2021-11-11 11:02:04 +00:00
m3o-actions
7d037fe871 Commit from m3o/m3o action 2021-11-11 11:00:15 +00:00
m3o-actions
53a197a685 Commit from m3o/m3o action 2021-11-11 10:57:32 +00:00
m3o-actions
a7586670e6 Commit from m3o/m3o action 2021-11-11 10:56:43 +00:00
m3o-actions
2b5509db64 Commit from m3o/m3o action 2021-11-11 10:55:40 +00:00
m3o-actions
03a720c4d0 Commit from m3o/m3o action 2021-11-11 10:54:44 +00:00
m3o-actions
581945da61 Commit from m3o/m3o action 2021-11-11 10:26:25 +00:00
m3o-actions
d27ecddd94 Commit from m3o/m3o action 2021-11-11 10:13:24 +00:00
m3o-actions
034d9aa5ac Commit from m3o/m3o action 2021-11-10 23:58:27 +00:00
m3o-actions
328997c217 Commit from m3o/m3o action 2021-11-10 22:29:50 +00:00
m3o-actions
f87a55000e Commit from m3o/m3o action 2021-11-10 22:17:37 +00:00
m3o-actions
5ec5e88b61 Commit from m3o/m3o action 2021-11-10 16:26:02 +00:00
m3o-actions
d664134226 Commit from m3o/m3o action 2021-11-10 16:21:04 +00:00
m3o-actions
20bb0adb52 Commit from m3o/m3o action 2021-11-10 16:16:45 +00:00
m3o-actions
b32923c69c Commit from m3o/m3o action 2021-11-10 16:15:20 +00:00
m3o-actions
bb8552ac72 Commit from m3o/m3o action 2021-11-10 16:00:58 +00:00
m3o-actions
2e2264a045 Commit from m3o/m3o action 2021-11-10 15:58:48 +00:00
m3o-actions
8fbc04d515 Commit from m3o/m3o action 2021-11-10 15:50:32 +00:00
m3o-actions
6c77e113d7 Commit from m3o/m3o action 2021-11-10 13:54:12 +00:00
m3o-actions
be500e861e Commit from m3o/m3o action 2021-11-10 13:11:50 +00:00
m3o-actions
8217b63c9a Commit from m3o/m3o action 2021-11-10 13:06:03 +00:00
m3o-actions
5e75ed6f44 Commit from m3o/m3o action 2021-11-10 12:39:48 +00:00
m3o-actions
3ea4ec9b77 Commit from m3o/m3o action 2021-11-10 12:37:48 +00:00
m3o-actions
6715cd7575 Commit from m3o/m3o action 2021-11-10 12:31:16 +00:00
m3o-actions
36fa586811 Commit from m3o/m3o action 2021-11-10 12:19:48 +00:00
m3o-actions
f3c2a87ba8 Commit from m3o/m3o action 2021-11-10 11:57:00 +00:00
m3o-actions
48a07e015a Commit from m3o/m3o action 2021-11-10 11:32:49 +00:00
m3o-actions
2deeb0ca70 Commit from m3o/m3o action 2021-11-10 11:05:04 +00:00
m3o-actions
1305ec64f5 Commit from m3o/m3o action 2021-11-10 10:55:08 +00:00
Janos Dobronszki
120c1cfe31 Run idempotent exaples as tests in CI (#7) 2021-11-10 09:37:45 +00:00
m3o-actions
3c1c9769fb Commit from m3o/m3o action 2021-11-10 09:21:08 +00:00
m3o-actions
9404bd621a Commit from m3o/m3o action 2021-11-10 09:20:30 +00:00
m3o-actions
429d8543ba Commit from m3o/m3o action 2021-11-10 09:16:45 +00:00
m3o-actions
0515ac3485 Commit from m3o/m3o action 2021-11-10 09:03:04 +00:00
m3o-actions
36ebf2726c Commit from m3o/m3o action 2021-11-10 07:02:27 +00:00
m3o-actions
13eb3a674c Commit from m3o/m3o action 2021-11-10 06:57:47 +00:00
m3o-actions
b724299623 Commit from m3o/m3o action 2021-11-10 06:57:03 +00:00
m3o-actions
a2eea8e982 Commit from m3o/m3o action 2021-11-09 15:01:52 +00:00
m3o-actions
b36641e39e Commit from m3o/m3o action 2021-11-09 11:39:14 +00:00
m3o-actions
e9f001a53c Commit from m3o/m3o action 2021-11-09 11:10:41 +00:00
m3o-actions
80c683fa2a Commit from m3o/m3o action 2021-11-09 10:50:05 +00:00
m3o-actions
7b1ff7cdba Commit from m3o/m3o action 2021-11-09 10:41:16 +00:00
m3o-actions
93b0465212 Commit from m3o/m3o action 2021-11-09 10:23:33 +00:00
m3o-actions
0c2f5b7138 Commit from m3o/m3o action 2021-11-09 10:11:09 +00:00
m3o-actions
0d4aacf4c1 Commit from m3o/m3o action 2021-11-09 09:59:49 +00:00
m3o-actions
3cd6a304e8 Commit from m3o/m3o action 2021-11-09 09:55:58 +00:00
m3o-actions
5ed7ec293a Commit from m3o/m3o action 2021-11-09 00:12:20 +00:00
m3o-actions
b69dce32b5 Commit from m3o/m3o action 2021-11-09 00:08:05 +00:00
m3o-actions
24a8774b65 Commit from m3o/m3o action 2021-11-08 23:58:17 +00:00
m3o-actions
c70c849348 Commit from m3o/m3o action 2021-11-08 23:56:42 +00:00
m3o-actions
48a87453db Commit from m3o/m3o action 2021-11-08 23:50:31 +00:00
m3o-actions
d02ff341b9 Commit from m3o/m3o action 2021-11-08 23:45:01 +00:00
m3o-actions
e357681055 Commit from m3o/m3o action 2021-11-08 23:38:39 +00:00
m3o-actions
01728ef128 Commit from m3o/m3o action 2021-11-08 23:25:53 +00:00
m3o-actions
57653a725d Commit from m3o/m3o action 2021-11-08 23:13:03 +00:00
m3o-actions
ceba4eac78 Commit from m3o/m3o action 2021-11-08 23:00:09 +00:00
m3o-actions
e2457aa0ef Commit from m3o/m3o action 2021-11-08 22:49:41 +00:00
m3o-actions
eff7396cfd Commit from m3o/m3o action 2021-11-08 22:16:22 +00:00
m3o-actions
b6914f82d4 Commit from m3o/m3o action 2021-11-08 22:05:24 +00:00
m3o-actions
e3e358df0b Commit from m3o/m3o action 2021-11-08 21:58:01 +00:00
m3o-actions
78900e379e Commit from m3o/m3o action 2021-11-08 17:01:54 +00:00
m3o-actions
39cf329baa Commit from m3o/m3o action 2021-11-08 15:54:16 +00:00
m3o-actions
c4df401021 Commit from m3o/m3o action 2021-11-08 15:42:22 +00:00
m3o-actions
7d5d0555b3 Commit from m3o/m3o action 2021-11-08 15:01:27 +00:00
m3o-actions
16e313b176 Commit from m3o/m3o action 2021-11-08 13:23:33 +00:00
m3o-actions
f5e55c81b0 Commit from m3o/m3o action 2021-11-08 11:36:04 +00:00
m3o-actions
d0307610bc Commit from m3o/m3o action 2021-11-08 10:59:15 +00:00
m3o-actions
cab87b9b3e Commit from m3o/m3o action 2021-11-05 22:42:46 +00:00
m3o-actions
c18a866b71 Commit from m3o/m3o action 2021-11-05 18:00:15 +00:00
m3o-actions
5f43c72002 Commit from m3o/m3o action 2021-11-05 17:23:25 +00:00
m3o-actions
d9c5465869 Commit from m3o/m3o action 2021-11-05 15:43:54 +00:00
m3o-actions
bf17b77f32 Commit from m3o/m3o action 2021-11-05 15:16:17 +00:00
m3o-actions
dc963b5c18 Commit from m3o/m3o action 2021-11-05 14:46:52 +00:00
m3o-actions
d0c9e6f959 Commit from m3o/m3o action 2021-11-05 14:46:11 +00:00
m3o-actions
87139ca743 Commit from m3o/m3o action 2021-11-05 14:44:14 +00:00
m3o-actions
c9438a2715 Commit from m3o/m3o action 2021-11-05 14:44:10 +00:00
m3o-actions
fcf0cacf5f Commit from m3o/m3o action 2021-11-05 12:06:56 +00:00
m3o-actions
dd375dcb39 Commit from m3o/m3o action 2021-11-04 22:07:58 +00:00
m3o-actions
df176092d8 Commit from m3o/m3o action 2021-11-04 14:40:35 +00:00
m3o-actions
5c96743ac2 Commit from m3o/m3o action 2021-11-04 12:19:32 +00:00
m3o-actions
2293c9ffcd Commit from m3o/m3o action 2021-11-04 12:12:06 +00:00
m3o-actions
6814ff2132 Commit from m3o/m3o action 2021-11-04 11:33:12 +00:00
m3o-actions
3b0248b764 Commit from m3o/m3o action 2021-11-04 10:31:23 +00:00
m3o-actions
b71caa6818 Commit from m3o/m3o action 2021-11-04 09:47:59 +00:00
m3o-actions
857cdfd2ad Commit from m3o/m3o action 2021-11-04 09:42:11 +00:00
m3o-actions
de3da7ad78 Commit from m3o/m3o action 2021-11-04 00:34:55 +00:00
m3o-actions
9661bd5ae1 Commit from m3o/m3o action 2021-11-04 00:31:43 +00:00
m3o-actions
4ffa2e1a25 Commit from m3o/m3o action 2021-11-03 23:56:08 +00:00
m3o-actions
bab7357a54 Commit from m3o/m3o action 2021-11-03 23:51:59 +00:00
m3o-actions
e5e197566d Commit from m3o/m3o action 2021-11-03 23:44:49 +00:00
m3o-actions
e256e24571 Commit from m3o/m3o action 2021-11-03 23:27:18 +00:00
m3o-actions
a72108fe32 Commit from m3o/m3o action 2021-11-03 22:01:40 +00:00
m3o-actions
a88d369ab2 Commit from m3o/m3o action 2021-11-03 22:01:12 +00:00
m3o-actions
784c4e4c37 Commit from m3o/m3o action 2021-11-03 21:55:24 +00:00
m3o-actions
2e374bf3b0 Commit from m3o/m3o action 2021-11-03 21:49:35 +00:00
m3o-actions
36ea54da44 Commit from m3o/m3o action 2021-11-03 21:44:16 +00:00
m3o-actions
6a5d769c70 Commit from m3o/m3o action 2021-11-03 17:09:53 +00:00
m3o-actions
5963caaa3f Commit from m3o/m3o action 2021-11-03 17:03:09 +00:00
m3o-actions
611202c283 Commit from m3o/m3o action 2021-11-03 16:59:37 +00:00
m3o-actions
1645b031e1 Commit from m3o/m3o action 2021-11-03 16:20:20 +00:00
m3o-actions
d87e334dca Commit from m3o/m3o action 2021-11-03 16:08:32 +00:00
m3o-actions
9a245d66ac Commit from m3o/m3o action 2021-11-03 15:50:29 +00:00
m3o-actions
7335a0576f Commit from m3o/m3o action 2021-11-03 15:36:34 +00:00
m3o-actions
aecab5372c Commit from m3o/m3o action 2021-11-03 15:16:55 +00:00
m3o-actions
a3f66cea0b Commit from m3o/m3o action 2021-11-03 14:15:29 +00:00
m3o-actions
2a5dc16cef Commit from m3o/m3o action 2021-11-03 14:12:51 +00:00
m3o-actions
3af01580b7 Commit from m3o/m3o action 2021-11-03 14:00:31 +00:00
m3o-actions
49e533797f Commit from m3o/m3o action 2021-11-03 11:49:43 +00:00
m3o-actions
2283f13e57 Commit from m3o/m3o action 2021-11-03 11:19:16 +00:00
Janos Dobronszki
e59c2bcc38 Add CI (#6) 2021-11-03 10:28:07 +00:00
m3o-actions
c6b213570b Commit from m3o/m3o action 2021-11-03 10:19:08 +00:00
m3o-actions
8e6e73a8eb Commit from m3o/m3o action 2021-11-02 19:13:21 +00:00
m3o-actions
075c121632 Commit from m3o/m3o action 2021-11-02 18:38:37 +00:00
m3o-actions
99e2f22d5b Commit from m3o/m3o action 2021-11-02 18:37:33 +00:00
m3o-actions
8623e7fec8 Commit from m3o/m3o action 2021-11-02 16:43:32 +00:00
m3o-actions
114660a002 Commit from m3o/m3o action 2021-11-02 16:31:05 +00:00
m3o-actions
913e2d609a Commit from m3o/m3o action 2021-11-02 16:01:40 +00:00
m3o-actions
ec70bb0b96 Commit from m3o/m3o action 2021-11-02 15:20:10 +00:00
m3o-actions
0e5e506abb Commit from m3o/m3o action 2021-11-02 15:15:35 +00:00
m3o-actions
96b0791847 Commit from m3o/m3o action 2021-11-02 14:59:05 +00:00
m3o-actions
15117f4033 Commit from m3o/m3o action 2021-11-02 14:55:18 +00:00
m3o-actions
716231b211 Commit from m3o/m3o action 2021-11-02 14:08:59 +00:00
m3o-actions
abbc8bcd49 Commit from m3o/m3o action 2021-11-02 14:08:34 +00:00
m3o-actions
c5f35e9f42 Commit from m3o/m3o action 2021-11-02 14:06:57 +00:00
m3o-actions
1b52b0f771 Commit from m3o/m3o action 2021-11-02 14:03:39 +00:00
m3o-actions
6533fdf6ff Commit from m3o/m3o action 2021-11-02 14:00:42 +00:00
m3o-actions
476fc61f51 Commit from m3o/m3o action 2021-11-02 13:52:46 +00:00
m3o-actions
fa2e8a5283 Commit from m3o/m3o action 2021-11-02 13:41:15 +00:00
m3o-actions
a8b7e20a0c Commit from m3o/m3o action 2021-11-02 13:31:19 +00:00
m3o-actions
d38b38c742 Commit from m3o/m3o action 2021-11-02 11:53:01 +00:00
m3o-actions
47e7a6709f Commit from m3o/m3o action 2021-11-02 11:49:54 +00:00
m3o-actions
68b5269093 Commit from m3o/m3o action 2021-11-02 11:36:55 +00:00
m3o-actions
4707018011 Commit from m3o/m3o action 2021-11-02 10:55:57 +00:00
m3o-actions
f3da9bd908 Commit from m3o/m3o action 2021-11-02 08:19:52 +00:00
m3o-actions
2ccc1a4d17 Commit from m3o/m3o action 2021-11-02 08:18:51 +00:00
m3o-actions
eff35e79ef Commit from m3o/m3o action 2021-11-02 07:44:22 +00:00
m3o-actions
fe077602a7 Commit from m3o/m3o action 2021-11-01 17:16:01 +00:00
m3o-actions
e2913e9e7c Commit from m3o/m3o action 2021-11-01 17:11:34 +00:00
m3o-actions
0561a7f7c2 Commit from m3o/m3o action 2021-11-01 17:09:11 +00:00
m3o-actions
21ded67c07 Commit from m3o/m3o action 2021-11-01 15:55:15 +00:00
m3o-actions
b3f128386d Commit from m3o/m3o action 2021-11-01 15:47:02 +00:00
m3o-actions
97f56e72a2 Commit from m3o/m3o action 2021-11-01 15:41:08 +00:00
m3o-actions
c64b4b029f Commit from m3o/m3o action 2021-10-31 13:53:09 +00:00
m3o-actions
5c6ed49281 Commit from m3o/m3o action 2021-10-31 13:51:20 +00:00
m3o-actions
6411450031 Commit from m3o/m3o action 2021-10-31 13:47:11 +00:00
m3o-actions
1c389d4cca Commit from m3o/m3o action 2021-10-30 11:56:34 +00:00
m3o-actions
0805168f1d Commit from m3o/m3o action 2021-10-30 11:51:28 +00:00
m3o-actions
429a6ad180 Commit from m3o/m3o action 2021-10-30 07:30:10 +00:00
m3o-actions
218188cbcf Commit from m3o/m3o action 2021-10-29 13:17:32 +00:00
m3o-actions
168985fe21 Commit from m3o/m3o action 2021-10-29 13:12:31 +00:00
m3o-actions
6d4b56721d Commit from m3o/m3o action 2021-10-29 13:12:23 +00:00
m3o-actions
9482db748c Commit from m3o/m3o action 2021-10-29 12:43:44 +00:00
m3o-actions
a3b4eba5f1 Commit from m3o/m3o action 2021-10-29 12:41:37 +00:00
m3o-actions
c84accfb12 Commit from m3o/m3o action 2021-10-29 12:34:38 +00:00
m3o-actions
a4c61983ce Commit from m3o/m3o action 2021-10-29 12:15:32 +00:00
m3o-actions
814f4826d6 Commit from m3o/m3o action 2021-10-29 12:14:54 +00:00
Asim Aslam
a142615a6b Update README.md 2021-10-29 12:07:10 +01:00
m3o-actions
7b95e8f58f Commit from m3o/m3o action 2021-10-29 11:05:31 +00:00
Asim Aslam
cdd1eea406 update readme 2021-10-29 11:58:04 +01:00
Asim Aslam
8604d436eb remove curl files 2021-10-29 11:49:15 +01:00
m3o-actions
eb73d115f2 Commit from m3o/m3o action 2021-10-29 10:44:29 +00:00
m3o-actions
4e64b77e47 Commit from m3o/m3o action 2021-10-29 10:40:25 +00:00
Asim Aslam
8e9779a8cb remove curl files 2021-10-29 11:39:33 +01:00
m3o-actions
c5c2867dc3 Commit from m3o/m3o action 2021-10-29 10:32:59 +00:00
Asim Aslam
0a3298c33b remove curl files 2021-10-29 11:03:26 +01:00
m3o-actions
5c34812294 Commit from m3o/m3o action 2021-10-29 09:09:35 +00:00
m3o-actions
2576812b54 Commit from m3o/m3o action 2021-10-29 08:41:22 +00:00
m3o-actions
8fc6fd6913 Commit from m3o/m3o action 2021-10-29 08:37:53 +00:00
m3o-actions
f3f53f865a Commit from m3o/m3o action 2021-10-29 08:13:31 +00:00
m3o-actions
1682d4075e Commit from m3o/m3o action 2021-10-29 08:12:32 +00:00
m3o-actions
c2ee05e2eb Commit from m3o/m3o action 2021-10-29 07:43:23 +00:00
m3o-actions
268689a87d Commit from m3o/m3o action 2021-10-29 07:31:06 +00:00
m3o-actions
e8c2e112f5 Commit from m3o/m3o action 2021-10-29 07:17:30 +00:00
m3o-actions
f5260050e4 Commit from m3o/m3o action 2021-10-29 07:15:05 +00:00
m3o-actions
f33dc1e44c Commit from m3o/m3o action 2021-10-29 06:59:53 +00:00
m3o-actions
ae73a4aca1 Commit from m3o/m3o action 2021-10-29 06:38:17 +00:00
Janos Dobronszki
87f310675d Update go.mod 2021-10-28 14:58:32 +01:00
m3o-actions
6b328d406c Commit from m3o/m3o action 2021-10-28 13:52:36 +00:00
Janos Dobronszki
aba344cf69 Delete go directory 2021-10-28 14:51:42 +01:00
m3o-actions
fced949d94 Commit from m3o/m3o action 2021-10-28 13:41:00 +00:00
Janos Dobronszki
ec8910b174 Delete go directory 2021-10-28 14:38:07 +01:00
m3o-actions
f8f41e7434 Commit from m3o/m3o action 2021-10-28 13:31:19 +00:00
Asim Aslam
55b73f2fc7 Update vanity.yaml 2021-10-28 12:08:20 +01:00
Asim Aslam
f2f62ad942 Merge branch 'master' of ssh://github.com/m3o/m3o-go 2021-09-17 11:30:41 +01:00
Asim Aslam
101c159dcf move vanity 2021-09-17 11:30:31 +01:00
Janos Dobronszki
a4f018a78d Remove type safe clients 2021-09-15 12:36:33 +01:00
Janos Dobronszki
726d1ccef6 Add separate service clients (#5) 2021-09-14 16:36:40 +01:00
Asim Aslam
ba48658a46 Update go.mod 2021-09-14 16:23:15 +01:00
Asim Aslam
8b37b56cb3 add vanity url code 2021-09-14 14:31:31 +01:00
Asim Aslam
0fe1baa576 Update README.md 2021-08-19 14:13:18 +01:00
Asim Aslam
824a47df5f Update README.md 2021-08-19 14:12:58 +01:00
Asim Aslam
3851006b3f Merge pull request #3 from lambdaR/timeout
Timeout
2021-06-11 20:48:18 +01:00
Daniel Joudat
6f6c4595f8 handling Timeout inside NewClient() 2021-06-11 22:03:59 +03:00
Daniel Joudat
b0c2e0b5c3 added timeout option 2021-06-11 20:19:07 +03:00
Asim Aslam
cf961b497e Merge branch 'master' of ssh://github.com/m3o/m3o-go 2021-04-21 16:08:13 +01:00
Asim Aslam
e335107786 Update README.md 2021-04-21 16:07:32 +01:00
Asim Aslam
384cfd9411 Update README.md 2021-04-21 16:06:25 +01:00
Asim Aslam
6d6edbe311 Update README.md 2021-04-21 16:06:06 +01:00
Asim Aslam
d273bcb0b9 move go mod to top level 2021-04-21 16:05:08 +01:00
Asim Aslam
8bfd7992ad Update README.md 2021-04-21 15:47:25 +01:00
Asim Aslam
c120cd2cf9 remove leading slash 2021-04-21 15:22:30 +01:00
Asim Aslam
facbb32e8e check nil options 2021-04-21 15:20:16 +01:00
Asim Aslam
4f3b55fa74 fix go mod 2021-04-21 15:18:07 +01:00
Asim Aslam
8d0170e51c Merge pull request #2 from m3o/fix-stream
use v1 api for stream
2021-04-21 13:53:14 +01:00
Asim Aslam
7b553cd374 use v1 api for stream 2021-04-21 13:52:21 +01:00
Janos Dobronszki
f7f75653ba Fix client to call v1api (#1) 2021-04-21 11:55:02 +01:00
Asim Aslam
c0d3889746 Update README.md 2021-02-06 09:24:10 +00:00
393 changed files with 15795 additions and 79 deletions

31
.github/workflows/generate.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Test Clients
on:
push:
branches:
- main
- beta
- ci
jobs:
generate:
name: Test Clients
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v2
with:
path: clients
#ref: main
- name: Test
working-directory: clients
env:
M3O_API_TOKEN: ${{ secrets.M3O_API_TOKEN }}
run: |
# stream is temporarily excluded as it hangs forever because test does not close connection
# @TODO remove "idempotent: true" from stream example
O=$(find . -name ".run" | grep -v stream | xargs -n1 dirname | xargs -n1 go run)
echo $O
if grep -q Detail "$O"; then
exit 1
fi

View File

@@ -1,6 +1,37 @@
# M3O Go Client
# M3O Go Client [![godoc](https://godoc.org/github.com/m3o/m3o-go?status.svg)](https://godoc.org/github.com/m3o/m3o-go) [![Go Report Card](https://goreportcard.com/badge/github.com/m3o/m3o-go)](https://goreportcard.com/report/github.com/m3o/m3o-go) [![Apache 2.0 License](https://img.shields.io/github/license/m3o/m3o-go)](https://github.com/m3o/m3o-go/blob/master/LICENSE)
By default the client connects to api.m3o.com/client
This is the Go client to access APIs on the M3O Platform
## Usage
Call a service using the generated client. Populate the `M3O_API_TOKEN` environment variable.
Import the package and initialise the service with your API token.
```go
package main
import(
"fmt"
"os"
"go.m3o.com/helloworld"
)
// Call returns a personalised "Hello $name" response
func main() {
helloworldService := helloworld.NewHelloworldService(os.Getenv("M3O_API_TOKEN"))
rsp, err := helloworldService.Call(&helloworld.CallRequest{
Name: "John",
})
fmt.Println(rsp, err)
}
```
## Generic Client
The generic client enables you to call any endpoint by name with freeform request/response types.
```go
package main
@@ -9,7 +40,7 @@ import (
"fmt"
"os"
"github.com/m3o/m3o-go/client"
"go.m3o.com/client"
)
type Request struct {
@@ -33,31 +64,21 @@ func main() {
req := &Request{
Name: "John",
}
var rsp Response
if err := c.Call("greeter", "Say.Hello", req, &rsp); err != nil {
if err := c.Call("helloworld", "call", req, &rsp); err != nil {
fmt.Println(err)
return
}
fmt.Println(rsp)
}
```
If you want to access your local micro:
```go
c := client.NewClient(client.Options{Local: true})
```
You can also set the api address explicitly:
```go
c := client.NewClient(client.Options{Address: "https://api.yourdomain.com/client"})
```
## Streaming
The client supports streaming
The client supports streaming but is not yet code generated. Use the following for streaming endpoints.
```go
package main
@@ -65,7 +86,7 @@ package main
import (
"fmt"
"github.com/micro/clients/go/client"
"go.m3o.com/client"
)
type Request struct {
@@ -76,10 +97,17 @@ type Response struct {
Count string `json:"count"`
}
func main() {
c := client.NewClient(&client.Options{Local: true})
var (
token, _ = os.Getenv("TOKEN")
)
stream, err := c.Stream("example", "Streamer.ServerStream", Request{Count: "10"})
func main() {
c := client.NewClient(nil)
// set your api token
c.SetToken(token)
stream, err := c.Stream("streams", "subscribe", Request{Count: "10"})
if err != nil {
fmt.Println(err)
return

59
address/address.go Executable file
View File

@@ -0,0 +1,59 @@
package address
import (
"go.m3o.com/client"
)
func NewAddressService(token string) *AddressService {
return &AddressService{
client: client.NewClient(&client.Options{
Token: token,
}),
}
}
type AddressService struct {
client *client.Client
}
// Lookup a list of UK addresses by postcode
func (t *AddressService) LookupPostcode(request *LookupPostcodeRequest) (*LookupPostcodeResponse, error) {
rsp := &LookupPostcodeResponse{}
return rsp, t.client.Call("address", "LookupPostcode", request, rsp)
}
type LookupPostcodeRequest struct {
// UK postcode e.g SW1A 2AA
Postcode string `json:"postcode"`
}
type LookupPostcodeResponse struct {
Addresses []Record `json:"addresses"`
}
type Record struct {
// building name
BuildingName string `json:"building_name"`
// the county
County string `json:"county"`
// line one of address
LineOne string `json:"line_one"`
// line two of address
LineTwo string `json:"line_two"`
// dependent locality
Locality string `json:"locality"`
// organisation if present
Organisation string `json:"organisation"`
// the postcode
Postcode string `json:"postcode"`
// the premise
Premise string `json:"premise"`
// street name
Street string `json:"street"`
// the complete address
Summary string `json:"summary"`
// post town
Town string `json:"town"`
}

39
answer/answer.go Executable file
View File

@@ -0,0 +1,39 @@
package answer
import (
"go.m3o.com/client"
)
func NewAnswerService(token string) *AnswerService {
return &AnswerService{
client: client.NewClient(&client.Options{
Token: token,
}),
}
}
type AnswerService struct {
client *client.Client
}
// Ask a question and receive an instant answer
func (t *AnswerService) Question(request *QuestionRequest) (*QuestionResponse, error) {
rsp := &QuestionResponse{}
return rsp, t.client.Call("answer", "Question", request, rsp)
}
type QuestionRequest struct {
// the question to answer
Query string `json:"query"`
}
type QuestionResponse struct {
// the answer to your question
Answer string `json:"answer"`
// any related image
Image string `json:"image"`
// a related url
Url string `json:"url"`
}

123
cache/cache.go vendored Executable file
View File

@@ -0,0 +1,123 @@
package cache
import (
"go.m3o.com/client"
)
func NewCacheService(token string) *CacheService {
return &CacheService{
client: client.NewClient(&client.Options{
Token: token,
}),
}
}
type CacheService struct {
client *client.Client
}
// Decrement a value (if it's a number). If key not found it is equivalent to set.
func (t *CacheService) Decrement(request *DecrementRequest) (*DecrementResponse, error) {
rsp := &DecrementResponse{}
return rsp, t.client.Call("cache", "Decrement", request, rsp)
}
// Delete a value from the cache. If key not found a success response is returned.
func (t *CacheService) Delete(request *DeleteRequest) (*DeleteResponse, error) {
rsp := &DeleteResponse{}
return rsp, t.client.Call("cache", "Delete", request, rsp)
}
// Get an item from the cache by key. If key is not found, an empty response is returned.
func (t *CacheService) Get(request *GetRequest) (*GetResponse, error) {
rsp := &GetResponse{}
return rsp, t.client.Call("cache", "Get", request, rsp)
}
// Increment a value (if it's a number). If key not found it is equivalent to set.
func (t *CacheService) Increment(request *IncrementRequest) (*IncrementResponse, error) {
rsp := &IncrementResponse{}
return rsp, t.client.Call("cache", "Increment", request, rsp)
}
// Set an item in the cache. Overwrites any existing value already set.
func (t *CacheService) Set(request *SetRequest) (*SetResponse, error) {
rsp := &SetResponse{}
return rsp, t.client.Call("cache", "Set", request, rsp)
}
type DecrementRequest struct {
// The key to decrement
Key string `json:"key"`
// The amount to decrement the value by
Value int64 `json:"value,string"`
}
type DecrementResponse struct {
// The key decremented
Key string `json:"key"`
// The new value
Value int64 `json:"value,string"`
}
type DeleteRequest struct {
// The key to delete
Key string `json:"key"`
}
type DeleteResponse struct {
// Returns "ok" if successful
Status string `json:"status"`
}
type GetRequest struct {
// The key to retrieve
Key string `json:"key"`
}
type GetResponse struct {
// The key
Key string `json:"key"`
// Time to live in seconds
Ttl int64 `json:"ttl,string"`
// The value
Value string `json:"value"`
}
type IncrementRequest struct {
// The key to increment
Key string `json:"key"`
// The amount to increment the value by
Value int64 `json:"value,string"`
}
type IncrementResponse struct {
// The key incremented
Key string `json:"key"`
// The new value
Value int64 `json:"value,string"`
}
type SetRequest struct {
// The key to update
Key string `json:"key"`
// Time to live in seconds
Ttl int64 `json:"ttl,string"`
// The value to set
Value string `json:"value"`
}
type SetResponse struct {
// Returns "ok" if successful
Status string `json:"status"`
}

View File

@@ -2,21 +2,22 @@ package client
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
"github.com/gorilla/websocket"
)
const (
// local address for api
localAddress = "http://localhost:8080/"
localAddress = "http://localhost:8080"
// public address for api
liveAddress = "https://api.m3o.com/"
liveAddress = "https://api.m3o.com"
)
// Options of the Client
@@ -29,6 +30,8 @@ type Options struct {
Address string
// Helper flag to help users connect to the default local address
Local bool
// set a timeout
Timeout time.Duration
}
// Request is the request of the generic `api-client` call
@@ -66,16 +69,28 @@ type Stream struct {
// NewClient returns a generic micro client that connects to live by default
func NewClient(options *Options) *Client {
ret := new(Client)
if options != nil {
ret.options = *options
} else {
ret.options = Options{
Address: liveAddress,
}
// no options provided
if options == nil {
return ret
}
if options != nil && options.Local {
if options.Token != "" {
ret.options.Token = options.Token
}
if options.Local {
ret.options.Address = localAddress
ret.options.Local = true
}
if options.Timeout > 0 {
ret.options.Timeout = options.Timeout
}
return ret
}
@@ -84,6 +99,11 @@ func (client *Client) SetToken(t string) {
client.options.Token = t
}
// SetTimeout sets the http client's timeout
func (client *Client) SetTimeout(d time.Duration) {
client.options.Timeout = d
}
// Call enables you to access any endpoint of any service on Micro
func (client *Client) Call(service, endpoint string, request, response interface{}) error {
// example curl: curl -XPOST -d '{"service": "go.micro.srv.greeter", "endpoint": "Say.Hello"}'
@@ -92,8 +112,9 @@ func (client *Client) Call(service, endpoint string, request, response interface
if err != nil {
return err
}
// TODO: make optional
uri.Path = "/client"
// set the url to go through the v1 api
uri.Path = "/v1/" + service + "/" + endpoint
b, err := marshalRequest(service, endpoint, request)
if err != nil {
@@ -107,12 +128,16 @@ func (client *Client) Call(service, endpoint string, request, response interface
// set the token if it exists
if len(client.options.Token) > 0 {
req.Header.Set("Authorization", "Bearer " + client.options.Token)
req.Header.Set("Authorization", "Bearer "+client.options.Token)
}
req.Header.Set("Content-Type", "application/json")
httpClient := &http.Client{}
// if user didn't specify Timeout the default is 0 i.e no timeout
httpClient := &http.Client{
Timeout: client.options.Timeout,
}
resp, err := httpClient.Do(req)
if err != nil {
return err
@@ -123,6 +148,9 @@ func (client *Client) Call(service, endpoint string, request, response interface
if err != nil {
return err
}
if !(resp.StatusCode >= 200 && resp.StatusCode < 300) {
return errors.New(string(body))
}
return unmarshalResponse(body, response)
}
@@ -137,8 +165,9 @@ func (client *Client) Stream(service, endpoint string, request interface{}) (*St
if err != nil {
return nil, err
}
// TODO: make optional
uri.Path = "/client/stream"
// set the url to go through the v1 api
uri.Path = "/v1/" + service + "/" + endpoint
// replace http with websocket
uri.Scheme = strings.Replace(uri.Scheme, "http", "ws", 1)
@@ -147,7 +176,7 @@ func (client *Client) Stream(service, endpoint string, request interface{}) (*St
header := make(http.Header)
// set the token if it exists
if len(client.options.Token) > 0 {
header.Set("Authorization", "Bearer " + client.options.Token)
header.Set("Authorization", "Bearer "+client.options.Token)
}
header.Set("Content-Type", "application/json")
@@ -183,25 +212,9 @@ func (s *Stream) Send(v interface{}) error {
}
func marshalRequest(service, endpoint string, v interface{}) ([]byte, error) {
b, err := json.Marshal(v)
if err != nil {
return nil, err
}
return json.Marshal(&Request{
Service: service,
Endpoint: endpoint,
Body: base64.StdEncoding.EncodeToString(b),
})
return json.Marshal(v)
}
func unmarshalResponse(body []byte, v interface{}) error {
rsp := new(Response)
if err := json.Unmarshal(body, rsp); err != nil {
return err
}
b, err := base64.StdEncoding.DecodeString(rsp.Body)
if err != nil {
return err
}
return json.Unmarshal(b, v)
return json.Unmarshal(body, &v)
}

View File

@@ -1,22 +1,24 @@
package client
import "testing"
type req struct {
Name string `json:"name"`
}
type rsp struct {
Msg string `json:"msg"`
}
import (
"os"
"testing"
)
func TestBasicCall(t *testing.T) {
response := rsp{}
if err := NewClient(nil).Call("go.micro.srv.greeter", "Say.Hello", req{Name: "John"}, &response); err != nil {
t.Fail()
if v := os.Getenv("IN_TRAVIS"); v == "yes" {
return
}
if response.Msg != "Hello John" {
t.Logf("Message is not as expected: %v", response.Msg)
t.Fail()
response := map[string]interface{}{}
if err := NewClient(&Options{
Token: os.Getenv("TOKEN"),
}).Call("groups", "list", map[string]interface{}{
"memberId": "random",
}, &response); err != nil {
t.Fatal(err)
}
if len(response) > 0 {
t.Fatal(len(response))
}
}

View File

@@ -1,5 +0,0 @@
module github.com/micro/clients/go/client
go 1.13
require github.com/gorilla/websocket v1.4.1

View File

@@ -1,2 +0,0 @@
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=

201
cmd/m3o-go-url/LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

134
cmd/m3o-go-url/README.md Normal file
View File

@@ -0,0 +1,134 @@
# M3O Go Vanity URL
M3O Go Vanity URL is a simple Go server that sets the custom url `go.m3o.com`
## Quickstart
Install and run the binary:
```
$ go get -u github.com/m3o-go/cmd/m3o-go-url
$ # update vanity.yaml
$ m3o-go-url
$ # open http://localhost:8080
```
### Google App Engine
Install [gcloud](https://cloud.google.com/sdk/downloads) and install Go App Engine component:
```
$ gcloud components install app-engine-go
```
Setup a [custom domain](https://cloud.google.com/appengine/docs/standard/python/using-custom-domains-and-ssl) for your app.
Get the application:
```
git clone https://github.com/GoogleCloudPlatform/govanityurls
cd govanityurls
```
Edit `vanity.yaml` to add any number of git repos. E.g., `customdomain.com/portmidi` will
serve the [https://github.com/rakyll/portmidi](https://github.com/rakyll/portmidi) repo.
```
paths:
/portmidi:
repo: https://github.com/rakyll/portmidi
```
You can add as many rules as you wish.
Deploy the app:
```
$ gcloud app deploy
```
That's it! You can use `go get` to get the package from your custom domain.
```
$ go get customdomain.com/portmidi
```
### Running in other environments
You can also deploy this as an App Engine Flexible app by changing the
`app.yaml` file:
```
runtime: go
env: flex
```
This project is a normal Go HTTP server, so you can also incorporate the
handler into larger Go servers.
## Configuration File
```
host: example.com
cache_max_age: 3600
paths:
/foo:
repo: https://github.com/example/foo
display: "https://github.com/example/foo https://github.com/example/foo/tree/master{/dir} https://github.com/example/foo/blob/master{/dir}/{file}#L{line}"
vcs: git
```
<table>
<thead>
<tr>
<th scope="col">Key</th>
<th scope="col">Required</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row"><code>cache_max_age</code></th>
<td>optional</td>
<td>The amount of time to cache package pages in seconds. Controls the <code>max-age</code> directive sent in the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control"><code>Cache-Control</code></a> HTTP header.</td>
</tr>
<tr>
<th scope="row"><code>host</code></th>
<td>optional</td>
<td>Host name to use in meta tags. If omitted, uses the App Engine default version host or the Host header on non-App Engine Standard environments. You can use this option to fix the host when using this service behind a reverse proxy or a <a href="https://cloud.google.com/appengine/docs/standard/go/how-requests-are-routed#routing_with_a_dispatch_file">custom dispatch file</a>.</td>
</tr>
<tr>
<th scope="row"><code>paths</code></th>
<td>required</td>
<td>Map of paths to path configurations. Each key is a path that will point to the root of a repository hosted elsewhere. The fields are documented in the Path Configuration section below.</td>
</tr>
</tbody>
</table>
### Path Configuration
<table>
<thead>
<tr>
<th scope="col">Key</th>
<th scope="col">Required</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row"><code>display</code></th>
<td>optional</td>
<td>The last three fields of the <a href="https://github.com/golang/gddo/wiki/Source-Code-Links"><code>go-source</code> meta tag</a>. If omitted, it is inferred from the code hosting service if possible.</td>
</tr>
<tr>
<th scope="row"><code>repo</code></th>
<td>required</td>
<td>Root URL of the repository as it would appear in <a href="https://golang.org/cmd/go/#hdr-Remote_import_paths"><code>go-import</code> meta tag</a>.</td>
</tr>
<tr>
<th scope="row"><code>vcs</code></th>
<td>required if ambiguous</td>
<td>If the version control system cannot be inferred (e.g. for Bitbucket or a custom domain), then this specifies the version control system as it would appear in <a href="https://golang.org/cmd/go/#hdr-Remote_import_paths"><code>go-import</code> meta tag</a>. This can be one of <code>git</code>, <code>hg</code>, <code>svn</code>, or <code>bzr</code>.</td>
</tr>
</tbody>
</table>

10
cmd/m3o-go-url/go.mod Normal file
View File

@@ -0,0 +1,10 @@
module github.com/m3o/m3o-go/cmd/m3o-go-url
go 1.13
require (
github.com/golang/protobuf v1.3.3 // indirect
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
google.golang.org/appengine v1.6.5
gopkg.in/yaml.v2 v2.2.8
)

13
cmd/m3o-go-url/go.sum Normal file
View File

@@ -0,0 +1,13 @@
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

225
cmd/m3o-go-url/handler.go Normal file
View File

@@ -0,0 +1,225 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// govanityurls serves Go vanity URLs.
package main
import (
"errors"
"fmt"
"html/template"
"net/http"
"sort"
"strings"
"gopkg.in/yaml.v2"
)
type handler struct {
host string
cacheControl string
paths pathConfigSet
}
type pathConfig struct {
path string
repo string
display string
vcs string
}
func newHandler(config []byte) (*handler, error) {
var parsed struct {
Host string `yaml:"host,omitempty"`
CacheAge *int64 `yaml:"cache_max_age,omitempty"`
Paths map[string]struct {
Repo string `yaml:"repo,omitempty"`
Display string `yaml:"display,omitempty"`
VCS string `yaml:"vcs,omitempty"`
} `yaml:"paths,omitempty"`
}
if err := yaml.Unmarshal(config, &parsed); err != nil {
return nil, err
}
h := &handler{host: parsed.Host}
cacheAge := int64(86400) // 24 hours (in seconds)
if parsed.CacheAge != nil {
cacheAge = *parsed.CacheAge
if cacheAge < 0 {
return nil, errors.New("cache_max_age is negative")
}
}
h.cacheControl = fmt.Sprintf("public, max-age=%d", cacheAge)
for path, e := range parsed.Paths {
pc := pathConfig{
path: strings.TrimSuffix(path, "/"),
repo: e.Repo,
display: e.Display,
vcs: e.VCS,
}
switch {
case e.Display != "":
// Already filled in.
case strings.HasPrefix(e.Repo, "https://github.com/"):
pc.display = fmt.Sprintf("%v %v/tree/master{/dir} %v/blob/master{/dir}/{file}#L{line}", e.Repo, e.Repo, e.Repo)
case strings.HasPrefix(e.Repo, "https://bitbucket.org"):
pc.display = fmt.Sprintf("%v %v/src/default{/dir} %v/src/default{/dir}/{file}#{file}-{line}", e.Repo, e.Repo, e.Repo)
}
switch {
case e.VCS != "":
// Already filled in.
if e.VCS != "bzr" && e.VCS != "git" && e.VCS != "hg" && e.VCS != "svn" {
return nil, fmt.Errorf("configuration for %v: unknown VCS %s", path, e.VCS)
}
case strings.HasPrefix(e.Repo, "https://github.com/"):
pc.vcs = "git"
default:
return nil, fmt.Errorf("configuration for %v: cannot infer VCS from %s", path, e.Repo)
}
h.paths = append(h.paths, pc)
}
sort.Sort(h.paths)
return h, nil
}
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
current := r.URL.Path
pc, subpath := h.paths.find(current)
if pc == nil && current == "/" {
h.serveIndex(w, r)
return
}
if pc == nil {
http.NotFound(w, r)
return
}
w.Header().Set("Cache-Control", h.cacheControl)
if err := vanityTmpl.Execute(w, struct {
Import string
Subpath string
Repo string
Display string
VCS string
}{
Import: h.Host(r) + pc.path,
Subpath: subpath,
Repo: pc.repo,
Display: pc.display,
VCS: pc.vcs,
}); err != nil {
http.Error(w, "cannot render the page", http.StatusInternalServerError)
}
}
func (h *handler) serveIndex(w http.ResponseWriter, r *http.Request) {
host := h.Host(r)
handlers := make([]string, len(h.paths))
for i, h := range h.paths {
handlers[i] = host + h.path
}
if err := indexTmpl.Execute(w, struct {
Host string
Handlers []string
}{
Host: host,
Handlers: handlers,
}); err != nil {
http.Error(w, "cannot render the page", http.StatusInternalServerError)
}
}
func (h *handler) Host(r *http.Request) string {
host := h.host
if host == "" {
host = defaultHost(r)
}
return host
}
var indexTmpl = template.Must(template.New("index").Parse(`<!DOCTYPE html>
<html>
<h1>{{.Host}}</h1>
<ul>
{{range .Handlers}}<li><a href="https://pkg.go.dev/{{.}}">{{.}}</a></li>{{end}}
</ul>
</html>
`))
var vanityTmpl = template.Must(template.New("vanity").Parse(`<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="go-import" content="{{.Import}} {{.VCS}} {{.Repo}}">
<meta name="go-source" content="{{.Import}} {{.Display}}">
<meta http-equiv="refresh" content="0; url=https://pkg.go.dev/{{.Import}}/{{.Subpath}}">
</head>
<body>
Nothing to see here; <a href="https://pkg.go.dev/{{.Import}}/{{.Subpath}}">see the package on pkg.go.dev</a>.
</body>
</html>`))
type pathConfigSet []pathConfig
func (pset pathConfigSet) Len() int {
return len(pset)
}
func (pset pathConfigSet) Less(i, j int) bool {
return pset[i].path < pset[j].path
}
func (pset pathConfigSet) Swap(i, j int) {
pset[i], pset[j] = pset[j], pset[i]
}
func (pset pathConfigSet) find(path string) (pc *pathConfig, subpath string) {
// Fast path with binary search to retrieve exact matches
// e.g. given pset ["/", "/abc", "/xyz"], path "/def" won't match.
i := sort.Search(len(pset), func(i int) bool {
return pset[i].path >= path
})
if i < len(pset) && pset[i].path == path {
return &pset[i], ""
}
if i > 0 && strings.HasPrefix(path, pset[i-1].path+"/") {
return &pset[i-1], path[len(pset[i-1].path)+1:]
}
// Slow path, now looking for the longest prefix/shortest subpath i.e.
// e.g. given pset ["/", "/abc/", "/abc/def/", "/xyz"/]
// * query "/abc/foo" returns "/abc/" with a subpath of "foo"
// * query "/x" returns "/" with a subpath of "x"
lenShortestSubpath := len(path)
var bestMatchConfig *pathConfig
// After binary search with the >= lexicographic comparison,
// nothing greater than i will be a prefix of path.
max := i
for i := 0; i < max; i++ {
ps := pset[i]
if len(ps.path) >= len(path) {
// We previously didn't find the path by search, so any
// route with equal or greater length is NOT a match.
continue
}
sSubpath := strings.TrimPrefix(path, ps.path)
if len(sSubpath) < lenShortestSubpath {
subpath = sSubpath
lenShortestSubpath = len(sSubpath)
bestMatchConfig = &pset[i]
}
}
return bestMatchConfig, subpath
}

View File

@@ -0,0 +1,315 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"bytes"
"io/ioutil"
"net/http"
"net/http/httptest"
"sort"
"testing"
)
func TestHandler(t *testing.T) {
tests := []struct {
name string
config string
path string
goImport string
goSource string
}{
{
name: "explicit display",
config: "host: example.com\n" +
"paths:\n" +
" /portmidi:\n" +
" repo: https://github.com/rakyll/portmidi\n" +
" display: https://github.com/rakyll/portmidi _ _\n",
path: "/portmidi",
goImport: "example.com/portmidi git https://github.com/rakyll/portmidi",
goSource: "example.com/portmidi https://github.com/rakyll/portmidi _ _",
},
{
name: "display GitHub inference",
config: "host: example.com\n" +
"paths:\n" +
" /portmidi:\n" +
" repo: https://github.com/rakyll/portmidi\n",
path: "/portmidi",
goImport: "example.com/portmidi git https://github.com/rakyll/portmidi",
goSource: "example.com/portmidi https://github.com/rakyll/portmidi https://github.com/rakyll/portmidi/tree/master{/dir} https://github.com/rakyll/portmidi/blob/master{/dir}/{file}#L{line}",
},
{
name: "Bitbucket Mercurial",
config: "host: example.com\n" +
"paths:\n" +
" /gopdf:\n" +
" repo: https://bitbucket.org/zombiezen/gopdf\n" +
" vcs: hg\n",
path: "/gopdf",
goImport: "example.com/gopdf hg https://bitbucket.org/zombiezen/gopdf",
goSource: "example.com/gopdf https://bitbucket.org/zombiezen/gopdf https://bitbucket.org/zombiezen/gopdf/src/default{/dir} https://bitbucket.org/zombiezen/gopdf/src/default{/dir}/{file}#{file}-{line}",
},
{
name: "Bitbucket Git",
config: "host: example.com\n" +
"paths:\n" +
" /mygit:\n" +
" repo: https://bitbucket.org/zombiezen/mygit\n" +
" vcs: git\n",
path: "/mygit",
goImport: "example.com/mygit git https://bitbucket.org/zombiezen/mygit",
goSource: "example.com/mygit https://bitbucket.org/zombiezen/mygit https://bitbucket.org/zombiezen/mygit/src/default{/dir} https://bitbucket.org/zombiezen/mygit/src/default{/dir}/{file}#{file}-{line}",
},
{
name: "subpath",
config: "host: example.com\n" +
"paths:\n" +
" /portmidi:\n" +
" repo: https://github.com/rakyll/portmidi\n" +
" display: https://github.com/rakyll/portmidi _ _\n",
path: "/portmidi/foo",
goImport: "example.com/portmidi git https://github.com/rakyll/portmidi",
goSource: "example.com/portmidi https://github.com/rakyll/portmidi _ _",
},
{
name: "subpath with trailing config slash",
config: "host: example.com\n" +
"paths:\n" +
" /portmidi/:\n" +
" repo: https://github.com/rakyll/portmidi\n" +
" display: https://github.com/rakyll/portmidi _ _\n",
path: "/portmidi/foo",
goImport: "example.com/portmidi git https://github.com/rakyll/portmidi",
goSource: "example.com/portmidi https://github.com/rakyll/portmidi _ _",
},
}
for _, test := range tests {
h, err := newHandler([]byte(test.config))
if err != nil {
t.Errorf("%s: newHandler: %v", test.name, err)
continue
}
s := httptest.NewServer(h)
resp, err := http.Get(s.URL + test.path)
if err != nil {
s.Close()
t.Errorf("%s: http.Get: %v", test.name, err)
continue
}
data, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
s.Close()
if resp.StatusCode != http.StatusOK {
t.Errorf("%s: status code = %s; want 200 OK", test.name, resp.Status)
}
if err != nil {
t.Errorf("%s: ioutil.ReadAll: %v", test.name, err)
continue
}
if got := findMeta(data, "go-import"); got != test.goImport {
t.Errorf("%s: meta go-import = %q; want %q", test.name, got, test.goImport)
}
if got := findMeta(data, "go-source"); got != test.goSource {
t.Errorf("%s: meta go-source = %q; want %q", test.name, got, test.goSource)
}
}
}
func TestBadConfigs(t *testing.T) {
badConfigs := []string{
"paths:\n" +
" /missingvcs:\n" +
" repo: https://bitbucket.org/zombiezen/gopdf\n",
"paths:\n" +
" /unknownvcs:\n" +
" repo: https://bitbucket.org/zombiezen/gopdf\n" +
" vcs: xyzzy\n",
"cache_max_age: -1\n" +
"paths:\n" +
" /portmidi:\n" +
" repo: https://github.com/rakyll/portmidi\n",
}
for _, config := range badConfigs {
_, err := newHandler([]byte(config))
if err == nil {
t.Errorf("expected config to produce an error, but did not:\n%s", config)
}
}
}
func findMeta(data []byte, name string) string {
var sep []byte
sep = append(sep, `<meta name="`...)
sep = append(sep, name...)
sep = append(sep, `" content="`...)
i := bytes.Index(data, sep)
if i == -1 {
return ""
}
content := data[i+len(sep):]
j := bytes.IndexByte(content, '"')
if j == -1 {
return ""
}
return string(content[:j])
}
func TestPathConfigSetFind(t *testing.T) {
tests := []struct {
paths []string
query string
want string
subpath string
}{
{
paths: []string{"/portmidi"},
query: "/portmidi",
want: "/portmidi",
},
{
paths: []string{"/portmidi"},
query: "/portmidi/",
want: "/portmidi",
},
{
paths: []string{"/portmidi"},
query: "/foo",
want: "",
},
{
paths: []string{"/portmidi"},
query: "/zzz",
want: "",
},
{
paths: []string{"/abc", "/portmidi", "/xyz"},
query: "/portmidi",
want: "/portmidi",
},
{
paths: []string{"/abc", "/portmidi", "/xyz"},
query: "/portmidi/foo",
want: "/portmidi",
subpath: "foo",
},
{
paths: []string{"/example/helloworld", "/", "/y", "/foo"},
query: "/x",
want: "/",
subpath: "x",
},
{
paths: []string{"/example/helloworld", "/", "/y", "/foo"},
query: "/",
want: "/",
subpath: "",
},
{
paths: []string{"/example/helloworld", "/", "/y", "/foo"},
query: "/example",
want: "/",
subpath: "example",
},
{
paths: []string{"/example/helloworld", "/", "/y", "/foo"},
query: "/example/foo",
want: "/",
subpath: "example/foo",
},
{
paths: []string{"/example/helloworld", "/", "/y", "/foo"},
query: "/y",
want: "/y",
},
{
paths: []string{"/example/helloworld", "/", "/y", "/foo"},
query: "/x/y/",
want: "/",
subpath: "x/y/",
},
{
paths: []string{"/example/helloworld", "/y", "/foo"},
query: "/x",
want: "",
},
}
emptyToNil := func(s string) string {
if s == "" {
return "<nil>"
}
return s
}
for _, test := range tests {
pset := make(pathConfigSet, len(test.paths))
for i := range test.paths {
pset[i].path = test.paths[i]
}
sort.Sort(pset)
pc, subpath := pset.find(test.query)
var got string
if pc != nil {
got = pc.path
}
if got != test.want || subpath != test.subpath {
t.Errorf("pathConfigSet(%v).find(%q) = %v, %v; want %v, %v",
test.paths, test.query, emptyToNil(got), subpath, emptyToNil(test.want), test.subpath)
}
}
}
func TestCacheHeader(t *testing.T) {
tests := []struct {
name string
config string
cacheControl string
}{
{
name: "default",
cacheControl: "public, max-age=86400",
},
{
name: "specify time",
config: "cache_max_age: 60\n",
cacheControl: "public, max-age=60",
},
{
name: "zero",
config: "cache_max_age: 0\n",
cacheControl: "public, max-age=0",
},
}
for _, test := range tests {
h, err := newHandler([]byte("paths:\n /portmidi:\n repo: https://github.com/rakyll/portmidi\n" +
test.config))
if err != nil {
t.Errorf("%s: newHandler: %v", test.name, err)
continue
}
s := httptest.NewServer(h)
resp, err := http.Get(s.URL + "/portmidi")
if err != nil {
t.Errorf("%s: http.Get: %v", test.name, err)
continue
}
resp.Body.Close()
got := resp.Header.Get("Cache-Control")
if got != test.cacheControl {
t.Errorf("%s: Cache-Control header = %q; want %q", test.name, got, test.cacheControl)
}
}
}

55
cmd/m3o-go-url/main.go Normal file
View File

@@ -0,0 +1,55 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"io/ioutil"
"log"
"net/http"
"os"
)
func main() {
var configPath string
switch len(os.Args) {
case 1:
configPath = "vanity.yaml"
case 2:
configPath = os.Args[1]
default:
log.Fatal("usage: m3o-go-url [CONFIG]")
}
vanity, err := ioutil.ReadFile(configPath)
if err != nil {
log.Fatal(err)
}
h, err := newHandler(vanity)
if err != nil {
log.Fatal(err)
}
http.Handle("/", h)
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatal(err)
}
}
func defaultHost(r *http.Request) string {
return r.Host
}

View File

@@ -0,0 +1,5 @@
host: go.m3o.com
paths:
/:
repo: https://github.com/m3o/m3o-go

128
crypto/crypto.go Executable file
View File

@@ -0,0 +1,128 @@
package crypto
import (
"go.m3o.com/client"
)
func NewCryptoService(token string) *CryptoService {
return &CryptoService{
client: client.NewClient(&client.Options{
Token: token,
}),
}
}
type CryptoService struct {
client *client.Client
}
// Returns the history for the previous close
func (t *CryptoService) History(request *HistoryRequest) (*HistoryResponse, error) {
rsp := &HistoryResponse{}
return rsp, t.client.Call("crypto", "History", request, rsp)
}
// Get news related to a currency
func (t *CryptoService) News(request *NewsRequest) (*NewsResponse, error) {
rsp := &NewsResponse{}
return rsp, t.client.Call("crypto", "News", request, rsp)
}
// Get the last price for a given crypto ticker
func (t *CryptoService) Price(request *PriceRequest) (*PriceResponse, error) {
rsp := &PriceResponse{}
return rsp, t.client.Call("crypto", "Price", request, rsp)
}
// Get the last quote for a given crypto ticker
func (t *CryptoService) Quote(request *QuoteRequest) (*QuoteResponse, error) {
rsp := &QuoteResponse{}
return rsp, t.client.Call("crypto", "Quote", request, rsp)
}
type Article struct {
// the date published
Date string `json:"date"`
// its description
Description string `json:"description"`
// the source
Source string `json:"source"`
// title of the article
Title string `json:"title"`
// the source url
Url string `json:"url"`
}
type HistoryRequest struct {
// the crypto symbol e.g BTCUSD
Symbol string `json:"symbol"`
}
type HistoryResponse struct {
// the close price
Close float64 `json:"close"`
// the date
Date string `json:"date"`
// the peak price
High float64 `json:"high"`
// the low price
Low float64 `json:"low"`
// the open price
Open float64 `json:"open"`
// the crypto symbol
Symbol string `json:"symbol"`
// the volume
Volume float64 `json:"volume"`
}
type NewsRequest struct {
// cryptocurrency ticker to request news for e.g BTC
Symbol string `json:"symbol"`
}
type NewsResponse struct {
// list of articles
Articles []Article `json:"articles"`
// symbol requested for
Symbol string `json:"symbol"`
}
type PriceRequest struct {
// the crypto symbol e.g BTCUSD
Symbol string `json:"symbol"`
}
type PriceResponse struct {
// the last price
Price float64 `json:"price"`
// the crypto symbol e.g BTCUSD
Symbol string `json:"symbol"`
}
type QuoteRequest struct {
// the crypto symbol e.g BTCUSD
Symbol string `json:"symbol"`
}
type QuoteResponse struct {
// the asking price
AskPrice float64 `json:"ask_price"`
// the ask size
AskSize float64 `json:"ask_size"`
// the bidding price
BidPrice float64 `json:"bid_price"`
// the bid size
BidSize float64 `json:"bid_size"`
// the crypto symbol
Symbol string `json:"symbol"`
// the UTC timestamp of the quote
Timestamp string `json:"timestamp"`
}

111
currency/currency.go Executable file
View File

@@ -0,0 +1,111 @@
package currency
import (
"go.m3o.com/client"
)
func NewCurrencyService(token string) *CurrencyService {
return &CurrencyService{
client: client.NewClient(&client.Options{
Token: token,
}),
}
}
type CurrencyService struct {
client *client.Client
}
// Codes returns the supported currency codes for the API
func (t *CurrencyService) Codes(request *CodesRequest) (*CodesResponse, error) {
rsp := &CodesResponse{}
return rsp, t.client.Call("currency", "Codes", request, rsp)
}
// Convert returns the currency conversion rate between two pairs e.g USD/GBP
func (t *CurrencyService) Convert(request *ConvertRequest) (*ConvertResponse, error) {
rsp := &ConvertResponse{}
return rsp, t.client.Call("currency", "Convert", request, rsp)
}
// Returns the historic rates for a currency on a given date
func (t *CurrencyService) History(request *HistoryRequest) (*HistoryResponse, error) {
rsp := &HistoryResponse{}
return rsp, t.client.Call("currency", "History", request, rsp)
}
// Rates returns the currency rates for a given code e.g USD
func (t *CurrencyService) Rates(request *RatesRequest) (*RatesResponse, error) {
rsp := &RatesResponse{}
return rsp, t.client.Call("currency", "Rates", request, rsp)
}
type Code struct {
// e.g United States Dollar
Currency string `json:"currency"`
// e.g USD
Name string `json:"name"`
}
type CodesRequest struct {
}
type CodesResponse struct {
Codes []Code `json:"codes"`
}
type ConvertRequest struct {
// optional amount to convert e.g 10.0
Amount float64 `json:"amount"`
// base code to convert from e.g USD
From string `json:"from"`
// target code to convert to e.g GBP
To string `json:"to"`
}
type ConvertResponse struct {
// converted amount e.g 7.10
Amount float64 `json:"amount"`
// the base code e.g USD
From string `json:"from"`
// conversion rate e.g 0.71
Rate float64 `json:"rate"`
// the target code e.g GBP
To string `json:"to"`
}
type HistoryRequest struct {
// currency code e.g USD
Code string `json:"code"`
// date formatted as YYYY-MM-DD
Date string `json:"date"`
}
type HistoryResponse struct {
// The code of the request
Code string `json:"code"`
// The date requested
Date string `json:"date"`
// The rate for the day as code:rate
Rates map[string]float64 `json:"rates"`
}
type RatesRequest struct {
// The currency code to get rates for e.g USD
Code string `json:"code"`
}
type RatesResponse struct {
// The code requested e.g USD
Code string `json:"code"`
// The rates for the given code as key-value pairs code:rate
Rates map[string]float64 `json:"rates"`
}

191
db/db.go Executable file
View File

@@ -0,0 +1,191 @@
package db
import (
"go.m3o.com/client"
)
func NewDbService(token string) *DbService {
return &DbService{
client: client.NewClient(&client.Options{
Token: token,
}),
}
}
type DbService struct {
client *client.Client
}
// Count records in a table
func (t *DbService) Count(request *CountRequest) (*CountResponse, error) {
rsp := &CountResponse{}
return rsp, t.client.Call("db", "Count", request, rsp)
}
// Create a record in the database. Optionally include an "id" field otherwise it's set automatically.
func (t *DbService) Create(request *CreateRequest) (*CreateResponse, error) {
rsp := &CreateResponse{}
return rsp, t.client.Call("db", "Create", request, rsp)
}
// Delete a record in the database by id.
func (t *DbService) Delete(request *DeleteRequest) (*DeleteResponse, error) {
rsp := &DeleteResponse{}
return rsp, t.client.Call("db", "Delete", request, rsp)
}
// Drop a table in the DB
func (t *DbService) DropTable(request *DropTableRequest) (*DropTableResponse, error) {
rsp := &DropTableResponse{}
return rsp, t.client.Call("db", "DropTable", request, rsp)
}
// List tables in the DB
func (t *DbService) ListTables(request *ListTablesRequest) (*ListTablesResponse, error) {
rsp := &ListTablesResponse{}
return rsp, t.client.Call("db", "ListTables", request, rsp)
}
// Read data from a table. Lookup can be by ID or via querying any field in the record.
func (t *DbService) Read(request *ReadRequest) (*ReadResponse, error) {
rsp := &ReadResponse{}
return rsp, t.client.Call("db", "Read", request, rsp)
}
// Rename a table
func (t *DbService) RenameTable(request *RenameTableRequest) (*RenameTableResponse, error) {
rsp := &RenameTableResponse{}
return rsp, t.client.Call("db", "RenameTable", request, rsp)
}
// Truncate the records in a table
func (t *DbService) Truncate(request *TruncateRequest) (*TruncateResponse, error) {
rsp := &TruncateResponse{}
return rsp, t.client.Call("db", "Truncate", request, rsp)
}
// Update a record in the database. Include an "id" in the record to update.
func (t *DbService) Update(request *UpdateRequest) (*UpdateResponse, error) {
rsp := &UpdateResponse{}
return rsp, t.client.Call("db", "Update", request, rsp)
}
type CountRequest struct {
// specify the table name
Table string `json:"table"`
}
type CountResponse struct {
// the number of records in the table
Count int32 `json:"count"`
}
type CreateRequest struct {
// JSON encoded record or records (can be array or object)
Record map[string]interface{} `json:"record"`
// Optional table name. Defaults to 'default'
Table string `json:"table"`
}
type CreateResponse struct {
// The id of the record (either specified or automatically created)
Id string `json:"id"`
}
type DeleteRequest struct {
// id of the record
Id string `json:"id"`
// Optional table name. Defaults to 'default'
Table string `json:"table"`
}
type DeleteResponse struct {
}
type DropTableRequest struct {
Table string `json:"table"`
}
type DropTableResponse struct {
}
type ListTablesRequest struct {
}
type ListTablesResponse struct {
// list of tables
Tables []string `json:"tables"`
}
type ReadRequest struct {
// Read by id. Equivalent to 'id == "your-id"'
Id string `json:"id"`
// Maximum number of records to return. Default limit is 25.
// Maximum limit is 1000. Anything higher will return an error.
Limit int32 `json:"limit"`
Offset int32 `json:"offset"`
// 'asc' (default), 'desc'
Order string `json:"order"`
// field name to order by
OrderBy string `json:"orderBy"`
// Examples: 'age >= 18', 'age >= 18 and verified == true'
// Comparison operators: '==', '!=', '<', '>', '<=', '>='
// Logical operator: 'and'
// Dot access is supported, eg: 'user.age == 11'
// Accessing list elements is not supported yet.
Query string `json:"query"`
// Optional table name. Defaults to 'default'
Table string `json:"table"`
}
type ReadResponse struct {
// JSON encoded records
Records []map[string]interface{} `json:"records"`
}
type RenameTableRequest struct {
// current table name
From string `json:"from"`
// new table name
To string `json:"to"`
}
type RenameTableResponse struct {
}
type TruncateRequest struct {
Table string `json:"table"`
}
type TruncateResponse struct {
}
type UpdateRequest struct {
// The id of the record. If not specified it is inferred from the 'id' field of the record
Id string `json:"id"`
// record, JSON object
Record map[string]interface{} `json:"record"`
// Optional table name. Defaults to 'default'
Table string `json:"table"`
}
type UpdateResponse struct {
}

43
email/email.go Executable file
View File

@@ -0,0 +1,43 @@
package email
import (
"go.m3o.com/client"
)
func NewEmailService(token string) *EmailService {
return &EmailService{
client: client.NewClient(&client.Options{
Token: token,
}),
}
}
type EmailService struct {
client *client.Client
}
// Send an email by passing in from, to, subject, and a text or html body
func (t *EmailService) Send(request *SendRequest) (*SendResponse, error) {
rsp := &SendResponse{}
return rsp, t.client.Call("email", "Send", request, rsp)
}
type SendRequest struct {
// the display name of the sender
From string `json:"from"`
// the html body
HtmlBody string `json:"html_body"`
// an optional reply to email address
ReplyTo string `json:"reply_to"`
// the email subject
Subject string `json:"subject"`
// the text body
TextBody string `json:"text_body"`
// the email address of the recipient
To string `json:"to"`
}
type SendResponse struct {
}

94
emoji/emoji.go Executable file
View File

@@ -0,0 +1,94 @@
package emoji
import (
"go.m3o.com/client"
)
func NewEmojiService(token string) *EmojiService {
return &EmojiService{
client: client.NewClient(&client.Options{
Token: token,
}),
}
}
type EmojiService struct {
client *client.Client
}
// Find an emoji by its alias e.g :beer:
func (t *EmojiService) Find(request *FindRequest) (*FindResponse, error) {
rsp := &FindResponse{}
return rsp, t.client.Call("emoji", "Find", request, rsp)
}
// Get the flag for a country. Requires country code e.g GB for great britain
func (t *EmojiService) Flag(request *FlagRequest) (*FlagResponse, error) {
rsp := &FlagResponse{}
return rsp, t.client.Call("emoji", "Flag", request, rsp)
}
// Print text and renders the emojis with aliases e.g
// let's grab a :beer: becomes let's grab a 🍺
func (t *EmojiService) Print(request *PrintRequest) (*PrintResponse, error) {
rsp := &PrintResponse{}
return rsp, t.client.Call("emoji", "Print", request, rsp)
}
// Send an emoji to anyone via SMS. Messages are sent in the form '<message> Sent from <from>'
func (t *EmojiService) Send(request *SendRequest) (*SendResponse, error) {
rsp := &SendResponse{}
return rsp, t.client.Call("emoji", "Send", request, rsp)
}
type FindRequest struct {
// the alias code e.g :beer:
Alias string `json:"alias"`
}
type FindResponse struct {
// the unicode emoji 🍺
Emoji string `json:"emoji"`
}
type FlagRequest struct {
// country code e.g GB
Code string `json:"code"`
}
type FlagResponse struct {
// the emoji flag
Flag string `json:"flag"`
}
type PrintRequest struct {
// text including any alias e.g let's grab a :beer:
Text string `json:"text"`
}
type PrintResponse struct {
// text with rendered emojis
Text string `json:"text"`
}
type SendRequest struct {
// the name of the sender from e.g Alice
From string `json:"from"`
// message to send including emoji aliases
Message string `json:"message"`
// phone number to send to (including international dialing code)
To string `json:"to"`
}
type SendResponse struct {
// whether or not it succeeded
Success bool `json:"success"`
}

244
evchargers/evchargers.go Executable file
View File

@@ -0,0 +1,244 @@
package evchargers
import (
"go.m3o.com/client"
)
func NewEvchargersService(token string) *EvchargersService {
return &EvchargersService{
client: client.NewClient(&client.Options{
Token: token,
}),
}
}
type EvchargersService struct {
client *client.Client
}
// Retrieve reference data as used by this API and in conjunction with the Search endpoint
func (t *EvchargersService) ReferenceData(request *ReferenceDataRequest) (*ReferenceDataResponse, error) {
rsp := &ReferenceDataResponse{}
return rsp, t.client.Call("evchargers", "ReferenceData", request, rsp)
}
// Search by giving a coordinate and a max distance, or bounding box and optional filters
func (t *EvchargersService) Search(request *SearchRequest) (*SearchResponse, error) {
rsp := &SearchResponse{}
return rsp, t.client.Call("evchargers", "Search", request, rsp)
}
type Address struct {
// Any comments about how to access the charger
AccessComments string `json:"access_comments"`
AddressLine1 string `json:"address_line_1"`
AddressLine2 string `json:"address_line_2"`
Country *Country `json:"country"`
CountryId string `json:"country_id"`
LatLng string `json:"lat_lng"`
Location *Coordinates `json:"location"`
Postcode string `json:"postcode"`
StateOrProvince string `json:"state_or_province"`
Title string `json:"title"`
Town string `json:"town"`
}
type BoundingBox struct {
BottomLeft *Coordinates `json:"bottom_left"`
TopRight *Coordinates `json:"top_right"`
}
type ChargerType struct {
Comments string `json:"comments"`
Id string `json:"id"`
// Is this 40KW+
IsFastChargeCapable bool `json:"is_fast_charge_capable"`
Title string `json:"title"`
}
type CheckinStatusType struct {
Id string `json:"id"`
IsAutomated bool `json:"is_automated"`
IsPositive bool `json:"is_positive"`
Title string `json:"title"`
}
type Connection struct {
// The amps offered
Amps float64 `json:"amps"`
ConnectionType *ConnectionType `json:"connection_type"`
// The ID of the connection type
ConnectionTypeId string `json:"connection_type_id"`
// The current
Current string `json:"current"`
Level *ChargerType `json:"level"`
// The level of charging power available
LevelId string `json:"level_id"`
// The power in KW
Power float64 `json:"power"`
Reference string `json:"reference"`
// The voltage offered
Voltage float64 `json:"voltage"`
}
type ConnectionType struct {
FormalName string `json:"formal_name"`
Id string `json:"id"`
IsDiscontinued bool `json:"is_discontinued"`
IsObsolete bool `json:"is_obsolete"`
Title string `json:"title"`
}
type Coordinates struct {
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
}
type Country struct {
ContinentCode string `json:"continent_code"`
Id string `json:"id"`
IsoCode string `json:"iso_code"`
Title string `json:"title"`
}
type CurrentType struct {
Description string `json:"description"`
Id string `json:"id"`
Title string `json:"title"`
}
type DataProvider struct {
Comments string `json:"comments"`
DataProviderStatusType *DataProviderStatusType `json:"data_provider_status_type"`
Id string `json:"id"`
// How is this data licensed
License string `json:"license"`
Title string `json:"title"`
Website string `json:"website"`
}
type DataProviderStatusType struct {
Id string `json:"id"`
IsProviderEnabled bool `json:"is_provider_enabled"`
Title string `json:"title"`
}
type Operator struct {
Comments string `json:"comments"`
ContactEmail string `json:"contact_email"`
FaultReportEmail string `json:"fault_report_email"`
Id string `json:"id"`
// Is this operator a private individual vs a company
IsPrivateIndividual bool `json:"is_private_individual"`
PhonePrimary string `json:"phone_primary"`
PhoneSecondary string `json:"phone_secondary"`
Title string `json:"title"`
Website string `json:"website"`
}
type Poi struct {
// The address
Address *Address `json:"address"`
// The connections available at this charge point
Connections []Connection `json:"connections"`
// The cost of charging
Cost string `json:"cost"`
// The ID of the data provider
DataProviderId string `json:"data_provider_id"`
// The ID of the charger
Id string `json:"id"`
// The number of charging points
NumPoints int64 `json:"num_points,string"`
// The operator
Operator *Operator `json:"operator"`
// The ID of the operator of the charger
OperatorId string `json:"operator_id"`
// The type of usage
UsageType *UsageType `json:"usage_type"`
// The type of usage for this charger point (is it public, membership required, etc)
UsageTypeId string `json:"usage_type_id"`
}
type ReferenceDataRequest struct {
}
type ReferenceDataResponse struct {
// The types of charger
ChargerTypes *ChargerType `json:"charger_types"`
// The types of checkin status
CheckinStatusTypes *CheckinStatusType `json:"checkin_status_types"`
// The types of connection
ConnectionTypes *ConnectionType `json:"connection_types"`
// The countries
Countries []Country `json:"countries"`
// The types of current
CurrentTypes *CurrentType `json:"current_types"`
// The providers of the charger data
DataProviders *DataProvider `json:"data_providers"`
// The companies operating the chargers
Operators []Operator `json:"operators"`
// The status of the charger
StatusTypes *StatusType `json:"status_types"`
// The status of a submission
SubmissionStatusTypes *SubmissionStatusType `json:"submission_status_types"`
// The different types of usage
UsageTypes *UsageType `json:"usage_types"`
// The types of user comment
UserCommentTypes *UserCommentType `json:"user_comment_types"`
}
type SearchRequest struct {
// Bounding box to search within (top left and bottom right coordinates)
Box *BoundingBox `json:"box"`
// IDs of the connection type
ConnectionTypes string `json:"connection_types"`
// Country ID
CountryId string `json:"country_id"`
// Search distance from point in metres, defaults to 5000m
Distance int64 `json:"distance,string"`
// Supported charging levels
Levels []string `json:"levels"`
// Coordinates from which to begin search
Location *Coordinates `json:"location"`
// Maximum number of results to return, defaults to 100
MaxResults int64 `json:"max_results,string"`
// Minimum power in KW. Note: data not available for many chargers
MinPower int64 `json:"min_power,string"`
// IDs of the the EV charger operator
Operators []string `json:"operators"`
// Usage of the charge point (is it public, membership required, etc)
UsageTypes string `json:"usage_types"`
}
type SearchResponse struct {
Pois []Poi `json:"pois"`
}
type StatusType struct {
Id string `json:"id"`
IsOperational bool `json:"is_operational"`
Title string `json:"title"`
}
type SubmissionStatusType struct {
Id string `json:"id"`
IsLive bool `json:"is_live"`
Title string `json:"title"`
}
type UsageType struct {
Id string `json:"id"`
IsAccessKeyRequired bool `json:"is_access_key_required"`
IsMembershipRequired bool `json:"is_membership_required"`
IsPayAtLocation bool `json:"is_pay_at_location"`
Title string `json:"title"`
}
type UserCommentType struct {
Id string `json:"id"`
Title string `json:"title"`
}

110
event/event.go Executable file
View File

@@ -0,0 +1,110 @@
package event
import (
"go.m3o.com/client"
)
func NewEventService(token string) *EventService {
return &EventService{
client: client.NewClient(&client.Options{
Token: token,
}),
}
}
type EventService struct {
client *client.Client
}
// Consume events from a given topic.
func (t *EventService) Consume(request *ConsumeRequest) (*ConsumeResponseStream, error) {
stream, err := t.client.Stream("event", "Consume", request)
if err != nil {
return nil, err
}
return &ConsumeResponseStream{
stream: stream,
}, nil
}
type ConsumeResponseStream struct {
stream *client.Stream
}
func (t *ConsumeResponseStream) Recv() (*ConsumeResponse, error) {
var rsp ConsumeResponse
if err := t.stream.Recv(&rsp); err != nil {
return nil, err
}
return &rsp, nil
}
// Publish a event to the event stream.
func (t *EventService) Publish(request *PublishRequest) (*PublishResponse, error) {
rsp := &PublishResponse{}
return rsp, t.client.Call("event", "Publish", request, rsp)
}
// Read stored events
func (t *EventService) Read(request *ReadRequest) (*ReadResponse, error) {
rsp := &ReadResponse{}
return rsp, t.client.Call("event", "Read", request, rsp)
}
type ConsumeRequest struct {
// Optional group for the subscription
Group string `json:"group"`
// Optional offset to read from e.g "2006-01-02T15:04:05.999Z07:00"
Offset string `json:"offset"`
// The topic to subscribe to
Topic string `json:"topic"`
}
type ConsumeResponse struct {
// Unique message id
Id string `json:"id"`
// The next json message on the topic
Message map[string]interface{} `json:"message"`
// Timestamp of publishing
Timestamp string `json:"timestamp"`
// The topic subscribed to
Topic string `json:"topic"`
}
type Ev struct {
// event id
Id string `json:"id"`
// event message
Message map[string]interface{} `json:"message"`
// event timestamp
Timestamp string `json:"timestamp"`
}
type PublishRequest struct {
// The json message to publish
Message map[string]interface{} `json:"message"`
// The topic to publish to
Topic string `json:"topic"`
}
type PublishResponse struct {
}
type ReadRequest struct {
// number of events to read; default 25
Limit int32 `json:"limit"`
// offset for the events; default 0
Offset int32 `json:"offset"`
// topic to read from
Topic string `json:"topic"`
}
type ReadResponse struct {
// the events
Events []Ev `json:"events"`
}

34
examples/address/README.md Executable file
View File

@@ -0,0 +1,34 @@
# Address
An [m3o.com](https://m3o.com) API. For example usage see [m3o.com/Address/api](https://m3o.com/Address/api).
Endpoints:
## LookupPostcode
Lookup a list of UK addresses by postcode
[https://m3o.com/address/api#LookupPostcode](https://m3o.com/address/api#LookupPostcode)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/address"
)
// Lookup a list of UK addresses by postcode
func LookupPostcode() {
addressService := address.NewAddressService(os.Getenv("M3O_API_TOKEN"))
rsp, err := addressService.LookupPostcode(&address.LookupPostcodeRequest{
Postcode: "SW1A 2AA",
})
fmt.Println(rsp, err)
}
```

View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/address"
)
// Lookup a list of UK addresses by postcode
func LookupPostcode() {
addressService := address.NewAddressService(os.Getenv("M3O_API_TOKEN"))
rsp, err := addressService.LookupPostcode(&address.LookupPostcodeRequest{
Postcode: "SW1A 2AA",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/address"
)
// Lookup a list of UK addresses by postcode
func main() {
addressService := address.NewAddressService(os.Getenv("M3O_API_TOKEN"))
rsp, err := addressService.LookupPostcode(&address.LookupPostcodeRequest{
Postcode: "SW1A 2AA",
})
fmt.Println(rsp, err)
}

34
examples/answer/README.md Executable file
View File

@@ -0,0 +1,34 @@
# Answer
An [m3o.com](https://m3o.com) API. For example usage see [m3o.com/Answer/api](https://m3o.com/Answer/api).
Endpoints:
## Question
Ask a question and receive an instant answer
[https://m3o.com/answer/api#Question](https://m3o.com/answer/api#Question)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/answer"
)
// Ask a question and receive an instant answer
func AskAquestion() {
answerService := answer.NewAnswerService(os.Getenv("M3O_API_TOKEN"))
rsp, err := answerService.Question(&answer.QuestionRequest{
Query: "microsoft",
})
fmt.Println(rsp, err)
}
```

View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/answer"
)
// Ask a question and receive an instant answer
func AskAquestion() {
answerService := answer.NewAnswerService(os.Getenv("M3O_API_TOKEN"))
rsp, err := answerService.Question(&answer.QuestionRequest{
Query: "microsoft",
})
fmt.Println(rsp, err)
}

View File

View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/answer"
)
// Ask a question and receive an instant answer
func main() {
answerService := answer.NewAnswerService(os.Getenv("M3O_API_TOKEN"))
rsp, err := answerService.Question(&answer.QuestionRequest{
Query: "microsoft",
})
fmt.Println(rsp, err)
}

149
examples/cache/README.md vendored Executable file
View File

@@ -0,0 +1,149 @@
# Cache
An [m3o.com](https://m3o.com) API. For example usage see [m3o.com/Cache/api](https://m3o.com/Cache/api).
Endpoints:
## Set
Set an item in the cache. Overwrites any existing value already set.
[https://m3o.com/cache/api#Set](https://m3o.com/cache/api#Set)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/cache"
)
// Set an item in the cache. Overwrites any existing value already set.
func SetAvalue() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Set(&cache.SetRequest{
Key: "foo",
Value: "bar",
})
fmt.Println(rsp, err)
}
```
## Get
Get an item from the cache by key. If key is not found, an empty response is returned.
[https://m3o.com/cache/api#Get](https://m3o.com/cache/api#Get)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/cache"
)
// Get an item from the cache by key. If key is not found, an empty response is returned.
func GetAvalue() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Get(&cache.GetRequest{
Key: "foo",
})
fmt.Println(rsp, err)
}
```
## Delete
Delete a value from the cache. If key not found a success response is returned.
[https://m3o.com/cache/api#Delete](https://m3o.com/cache/api#Delete)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/cache"
)
// Delete a value from the cache. If key not found a success response is returned.
func DeleteAvalue() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Delete(&cache.DeleteRequest{
Key: "foo",
})
fmt.Println(rsp, err)
}
```
## Increment
Increment a value (if it's a number). If key not found it is equivalent to set.
[https://m3o.com/cache/api#Increment](https://m3o.com/cache/api#Increment)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/cache"
)
// Increment a value (if it's a number). If key not found it is equivalent to set.
func IncrementAvalue() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Increment(&cache.IncrementRequest{
Key: "counter",
Value: 2,
})
fmt.Println(rsp, err)
}
```
## Decrement
Decrement a value (if it's a number). If key not found it is equivalent to set.
[https://m3o.com/cache/api#Decrement](https://m3o.com/cache/api#Decrement)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/cache"
)
// Decrement a value (if it's a number). If key not found it is equivalent to set.
func DecrementAvalue() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Decrement(&cache.DecrementRequest{
Key: "counter",
Value: 2,
})
fmt.Println(rsp, err)
}
```

18
examples/cache/decrement/decrementAValue.go vendored Executable file
View File

@@ -0,0 +1,18 @@
package example
import (
"fmt"
"os"
"go.m3o.com/cache"
)
// Decrement a value (if it's a number). If key not found it is equivalent to set.
func DecrementAvalue() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Decrement(&cache.DecrementRequest{
Key: "counter",
Value: 2,
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,19 @@
package main
import (
"fmt"
"os"
"go.m3o.com/cache"
)
// Decrement a value (if it's a number). If key not found it is equivalent to set.
func main() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Decrement(&cache.DecrementRequest{
Key: "counter",
Value: 2,
})
fmt.Println(rsp, err)
}

17
examples/cache/delete/deleteAValue.go vendored Executable file
View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/cache"
)
// Delete a value from the cache. If key not found a success response is returned.
func DeleteAvalue() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Delete(&cache.DeleteRequest{
Key: "foo",
})
fmt.Println(rsp, err)
}

18
examples/cache/delete/deleteAValue/main.go vendored Executable file
View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/cache"
)
// Delete a value from the cache. If key not found a success response is returned.
func main() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Delete(&cache.DeleteRequest{
Key: "foo",
})
fmt.Println(rsp, err)
}

17
examples/cache/get/getAValue.go vendored Executable file
View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/cache"
)
// Get an item from the cache by key. If key is not found, an empty response is returned.
func GetAvalue() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Get(&cache.GetRequest{
Key: "foo",
})
fmt.Println(rsp, err)
}

18
examples/cache/get/getAValue/main.go vendored Executable file
View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/cache"
)
// Get an item from the cache by key. If key is not found, an empty response is returned.
func main() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Get(&cache.GetRequest{
Key: "foo",
})
fmt.Println(rsp, err)
}

18
examples/cache/increment/incrementAValue.go vendored Executable file
View File

@@ -0,0 +1,18 @@
package example
import (
"fmt"
"os"
"go.m3o.com/cache"
)
// Increment a value (if it's a number). If key not found it is equivalent to set.
func IncrementAvalue() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Increment(&cache.IncrementRequest{
Key: "counter",
Value: 2,
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,19 @@
package main
import (
"fmt"
"os"
"go.m3o.com/cache"
)
// Increment a value (if it's a number). If key not found it is equivalent to set.
func main() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Increment(&cache.IncrementRequest{
Key: "counter",
Value: 2,
})
fmt.Println(rsp, err)
}

18
examples/cache/set/setAValue.go vendored Executable file
View File

@@ -0,0 +1,18 @@
package example
import (
"fmt"
"os"
"go.m3o.com/cache"
)
// Set an item in the cache. Overwrites any existing value already set.
func SetAvalue() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Set(&cache.SetRequest{
Key: "foo",
Value: "bar",
})
fmt.Println(rsp, err)
}

0
examples/cache/set/setAValue/.run vendored Executable file
View File

19
examples/cache/set/setAValue/main.go vendored Executable file
View File

@@ -0,0 +1,19 @@
package main
import (
"fmt"
"os"
"go.m3o.com/cache"
)
// Set an item in the cache. Overwrites any existing value already set.
func main() {
cacheService := cache.NewCacheService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cacheService.Set(&cache.SetRequest{
Key: "foo",
Value: "bar",
})
fmt.Println(rsp, err)
}

118
examples/crypto/README.md Executable file
View File

@@ -0,0 +1,118 @@
# Crypto
An [m3o.com](https://m3o.com) API. For example usage see [m3o.com/Crypto/api](https://m3o.com/Crypto/api).
Endpoints:
## Quote
Get the last quote for a given crypto ticker
[https://m3o.com/crypto/api#Quote](https://m3o.com/crypto/api#Quote)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/crypto"
)
// Get the last quote for a given crypto ticker
func GetAcryptocurrencyQuote() {
cryptoService := crypto.NewCryptoService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cryptoService.Quote(&crypto.QuoteRequest{
Symbol: "BTCUSD",
})
fmt.Println(rsp, err)
}
```
## History
Returns the history for the previous close
[https://m3o.com/crypto/api#History](https://m3o.com/crypto/api#History)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/crypto"
)
// Returns the history for the previous close
func GetPreviousClose() {
cryptoService := crypto.NewCryptoService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cryptoService.History(&crypto.HistoryRequest{
Symbol: "BTCUSD",
})
fmt.Println(rsp, err)
}
```
## News
Get news related to a currency
[https://m3o.com/crypto/api#News](https://m3o.com/crypto/api#News)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/crypto"
)
// Get news related to a currency
func GetCryptocurrencyNews() {
cryptoService := crypto.NewCryptoService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cryptoService.News(&crypto.NewsRequest{
Symbol: "BTCUSD",
})
fmt.Println(rsp, err)
}
```
## Price
Get the last price for a given crypto ticker
[https://m3o.com/crypto/api#Price](https://m3o.com/crypto/api#Price)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/crypto"
)
// Get the last price for a given crypto ticker
func GetCryptocurrencyPrice() {
cryptoService := crypto.NewCryptoService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cryptoService.Price(&crypto.PriceRequest{
Symbol: "BTCUSD",
})
fmt.Println(rsp, err)
}
```

View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/crypto"
)
// Returns the history for the previous close
func GetPreviousClose() {
cryptoService := crypto.NewCryptoService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cryptoService.History(&crypto.HistoryRequest{
Symbol: "BTCUSD",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/crypto"
)
// Returns the history for the previous close
func main() {
cryptoService := crypto.NewCryptoService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cryptoService.History(&crypto.HistoryRequest{
Symbol: "BTCUSD",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/crypto"
)
// Get news related to a currency
func GetCryptocurrencyNews() {
cryptoService := crypto.NewCryptoService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cryptoService.News(&crypto.NewsRequest{
Symbol: "BTCUSD",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/crypto"
)
// Get news related to a currency
func main() {
cryptoService := crypto.NewCryptoService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cryptoService.News(&crypto.NewsRequest{
Symbol: "BTCUSD",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/crypto"
)
// Get the last price for a given crypto ticker
func GetCryptocurrencyPrice() {
cryptoService := crypto.NewCryptoService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cryptoService.Price(&crypto.PriceRequest{
Symbol: "BTCUSD",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/crypto"
)
// Get the last price for a given crypto ticker
func main() {
cryptoService := crypto.NewCryptoService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cryptoService.Price(&crypto.PriceRequest{
Symbol: "BTCUSD",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/crypto"
)
// Get the last quote for a given crypto ticker
func GetAcryptocurrencyQuote() {
cryptoService := crypto.NewCryptoService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cryptoService.Quote(&crypto.QuoteRequest{
Symbol: "BTCUSD",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/crypto"
)
// Get the last quote for a given crypto ticker
func main() {
cryptoService := crypto.NewCryptoService(os.Getenv("M3O_API_TOKEN"))
rsp, err := cryptoService.Quote(&crypto.QuoteRequest{
Symbol: "BTCUSD",
})
fmt.Println(rsp, err)
}

149
examples/currency/README.md Executable file
View File

@@ -0,0 +1,149 @@
# Currency
An [m3o.com](https://m3o.com) API. For example usage see [m3o.com/Currency/api](https://m3o.com/Currency/api).
Endpoints:
## Codes
Codes returns the supported currency codes for the API
[https://m3o.com/currency/api#Codes](https://m3o.com/currency/api#Codes)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/currency"
)
// Codes returns the supported currency codes for the API
func GetSupportedCodes() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.Codes(&currency.CodesRequest{
})
fmt.Println(rsp, err)
}
```
## Rates
Rates returns the currency rates for a given code e.g USD
[https://m3o.com/currency/api#Rates](https://m3o.com/currency/api#Rates)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/currency"
)
// Rates returns the currency rates for a given code e.g USD
func GetRatesForUsd() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.Rates(&currency.RatesRequest{
Code: "USD",
})
fmt.Println(rsp, err)
}
```
## Convert
Convert returns the currency conversion rate between two pairs e.g USD/GBP
[https://m3o.com/currency/api#Convert](https://m3o.com/currency/api#Convert)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/currency"
)
// Convert returns the currency conversion rate between two pairs e.g USD/GBP
func ConvertUsdToGbp() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.Convert(&currency.ConvertRequest{
From: "USD",
To: "GBP",
})
fmt.Println(rsp, err)
}
```
## Convert
Convert returns the currency conversion rate between two pairs e.g USD/GBP
[https://m3o.com/currency/api#Convert](https://m3o.com/currency/api#Convert)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/currency"
)
// Convert returns the currency conversion rate between two pairs e.g USD/GBP
func Convert10usdToGbp() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.Convert(&currency.ConvertRequest{
Amount: 10,
From: "USD",
To: "GBP",
})
fmt.Println(rsp, err)
}
```
## History
Returns the historic rates for a currency on a given date
[https://m3o.com/currency/api#History](https://m3o.com/currency/api#History)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/currency"
)
// Returns the historic rates for a currency on a given date
func HistoricRatesForAcurrency() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.History(&currency.HistoryRequest{
Code: "USD",
Date: "2021-05-30",
})
fmt.Println(rsp, err)
}
```

View File

@@ -0,0 +1,15 @@
package example
import (
"fmt"
"os"
"go.m3o.com/currency"
)
// Codes returns the supported currency codes for the API
func GetSupportedCodes() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.Codes(&currency.CodesRequest{})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,16 @@
package main
import (
"fmt"
"os"
"go.m3o.com/currency"
)
// Codes returns the supported currency codes for the API
func main() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.Codes(&currency.CodesRequest{})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,19 @@
package example
import (
"fmt"
"os"
"go.m3o.com/currency"
)
// Convert returns the currency conversion rate between two pairs e.g USD/GBP
func Convert10usdToGbp() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.Convert(&currency.ConvertRequest{
Amount: 10,
From: "USD",
To: "GBP",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,20 @@
package main
import (
"fmt"
"os"
"go.m3o.com/currency"
)
// Convert returns the currency conversion rate between two pairs e.g USD/GBP
func main() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.Convert(&currency.ConvertRequest{
Amount: 10,
From: "USD",
To: "GBP",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package example
import (
"fmt"
"os"
"go.m3o.com/currency"
)
// Convert returns the currency conversion rate between two pairs e.g USD/GBP
func ConvertUsdToGbp() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.Convert(&currency.ConvertRequest{
From: "USD",
To: "GBP",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,19 @@
package main
import (
"fmt"
"os"
"go.m3o.com/currency"
)
// Convert returns the currency conversion rate between two pairs e.g USD/GBP
func main() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.Convert(&currency.ConvertRequest{
From: "USD",
To: "GBP",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package example
import (
"fmt"
"os"
"go.m3o.com/currency"
)
// Returns the historic rates for a currency on a given date
func HistoricRatesForAcurrency() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.History(&currency.HistoryRequest{
Code: "USD",
Date: "2021-05-30",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,19 @@
package main
import (
"fmt"
"os"
"go.m3o.com/currency"
)
// Returns the historic rates for a currency on a given date
func main() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.History(&currency.HistoryRequest{
Code: "USD",
Date: "2021-05-30",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/currency"
)
// Rates returns the currency rates for a given code e.g USD
func GetRatesForUsd() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.Rates(&currency.RatesRequest{
Code: "USD",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/currency"
)
// Rates returns the currency rates for a given code e.g USD
func main() {
currencyService := currency.NewCurrencyService(os.Getenv("M3O_API_TOKEN"))
rsp, err := currencyService.Rates(&currency.RatesRequest{
Code: "USD",
})
fmt.Println(rsp, err)
}

270
examples/db/README.md Executable file
View File

@@ -0,0 +1,270 @@
# Db
An [m3o.com](https://m3o.com) API. For example usage see [m3o.com/Db/api](https://m3o.com/Db/api).
Endpoints:
## Update
Update a record in the database. Include an "id" in the record to update.
[https://m3o.com/db/api#Update](https://m3o.com/db/api#Update)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/db"
)
// Update a record in the database. Include an "id" in the record to update.
func UpdateArecord() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Update(&db.UpdateRequest{
Record: map[string]interface{}{
"id": "1",
"age": 43,
},
Table: "users",
})
fmt.Println(rsp, err)
}
```
## RenameTable
Rename a table
[https://m3o.com/db/api#RenameTable](https://m3o.com/db/api#RenameTable)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/db"
)
// Rename a table
func RenameTable() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.RenameTable(&db.RenameTableRequest{
From: "events",
To: "events_backup",
})
fmt.Println(rsp, err)
}
```
## Create
Create a record in the database. Optionally include an "id" field otherwise it's set automatically.
[https://m3o.com/db/api#Create](https://m3o.com/db/api#Create)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/db"
)
// Create a record in the database. Optionally include an "id" field otherwise it's set automatically.
func CreateArecord() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Create(&db.CreateRequest{
Record: map[string]interface{}{
"isActive": true,
"id": "1",
"name": "Jane",
"age": 42,
},
Table: "users",
})
fmt.Println(rsp, err)
}
```
## Read
Read data from a table. Lookup can be by ID or via querying any field in the record.
[https://m3o.com/db/api#Read](https://m3o.com/db/api#Read)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/db"
)
// Read data from a table. Lookup can be by ID or via querying any field in the record.
func ReadRecords() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Read(&db.ReadRequest{
Query: "age == 43",
Table: "users",
})
fmt.Println(rsp, err)
}
```
## Delete
Delete a record in the database by id.
[https://m3o.com/db/api#Delete](https://m3o.com/db/api#Delete)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/db"
)
// Delete a record in the database by id.
func DeleteArecord() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Delete(&db.DeleteRequest{
Id: "1",
Table: "users",
})
fmt.Println(rsp, err)
}
```
## Truncate
Truncate the records in a table
[https://m3o.com/db/api#Truncate](https://m3o.com/db/api#Truncate)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/db"
)
// Truncate the records in a table
func TruncateTable() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Truncate(&db.TruncateRequest{
Table: "users",
})
fmt.Println(rsp, err)
}
```
## DropTable
Drop a table in the DB
[https://m3o.com/db/api#DropTable](https://m3o.com/db/api#DropTable)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/db"
)
// Drop a table in the DB
func DropTable() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.DropTable(&db.DropTableRequest{
Table: "users",
})
fmt.Println(rsp, err)
}
```
## Count
Count records in a table
[https://m3o.com/db/api#Count](https://m3o.com/db/api#Count)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/db"
)
// Count records in a table
func CountEntriesInAtable() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Count(&db.CountRequest{
Table: "users",
})
fmt.Println(rsp, err)
}
```
## ListTables
List tables in the DB
[https://m3o.com/db/api#ListTables](https://m3o.com/db/api#ListTables)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/db"
)
// List tables in the DB
func ListTables() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.ListTables(&db.ListTablesRequest{
})
fmt.Println(rsp, err)
}
```

View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Count records in a table
func CountEntriesInAtable() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Count(&db.CountRequest{
Table: "users",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Count records in a table
func main() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Count(&db.CountRequest{
Table: "users",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,23 @@
package example
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Create a record in the database. Optionally include an "id" field otherwise it's set automatically.
func CreateArecord() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Create(&db.CreateRequest{
Record: map[string]interface{}{
"id": "1",
"name": "Jane",
"age": 42,
"isActive": true,
},
Table: "users",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,24 @@
package main
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Create a record in the database. Optionally include an "id" field otherwise it's set automatically.
func main() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Create(&db.CreateRequest{
Record: map[string]interface{}{
"id": "1",
"name": "Jane",
"age": 42,
"isActive": true,
},
Table: "users",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package example
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Delete a record in the database by id.
func DeleteArecord() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Delete(&db.DeleteRequest{
Id: "1",
Table: "users",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,19 @@
package main
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Delete a record in the database by id.
func main() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Delete(&db.DeleteRequest{
Id: "1",
Table: "users",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Drop a table in the DB
func main() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.DropTable(&db.DropTableRequest{
Table: "users",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,16 @@
package main
import (
"fmt"
"os"
"go.m3o.com/db"
)
// List tables in the DB
func main() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.ListTables(&db.ListTablesRequest{})
fmt.Println(rsp, err)
}

18
examples/db/read/readRecords.go Executable file
View File

@@ -0,0 +1,18 @@
package example
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Read data from a table. Lookup can be by ID or via querying any field in the record.
func ReadRecords() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Read(&db.ReadRequest{
Query: "age == 43",
Table: "users",
})
fmt.Println(rsp, err)
}

View File

View File

@@ -0,0 +1,19 @@
package main
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Read data from a table. Lookup can be by ID or via querying any field in the record.
func main() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Read(&db.ReadRequest{
Query: "age == 43",
Table: "users",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,19 @@
package main
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Rename a table
func main() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.RenameTable(&db.RenameTableRequest{
From: "events",
To: "events_backup",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Truncate the records in a table
func TruncateTable() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Truncate(&db.TruncateRequest{
Table: "users",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Truncate the records in a table
func main() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Truncate(&db.TruncateRequest{
Table: "users",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,21 @@
package example
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Update a record in the database. Include an "id" in the record to update.
func UpdateArecord() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Update(&db.UpdateRequest{
Record: map[string]interface{}{
"id": "1",
"age": 43,
},
Table: "users",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,22 @@
package main
import (
"fmt"
"os"
"go.m3o.com/db"
)
// Update a record in the database. Include an "id" in the record to update.
func main() {
dbService := db.NewDbService(os.Getenv("M3O_API_TOKEN"))
rsp, err := dbService.Update(&db.UpdateRequest{
Record: map[string]interface{}{
"id": "1",
"age": 43,
},
Table: "users",
})
fmt.Println(rsp, err)
}

38
examples/email/README.md Executable file
View File

@@ -0,0 +1,38 @@
# Email
An [m3o.com](https://m3o.com) API. For example usage see [m3o.com/Email/api](https://m3o.com/Email/api).
Endpoints:
## Send
Send an email by passing in from, to, subject, and a text or html body
[https://m3o.com/email/api#Send](https://m3o.com/email/api#Send)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/email"
)
// Send an email by passing in from, to, subject, and a text or html body
func SendEmail() {
emailService := email.NewEmailService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emailService.Send(&email.SendRequest{
From: "Awesome Dot Com",
Subject: "Email verification",
TextBody: `Hi there,
Please verify your email by clicking this link: $micro_verification_link`,
})
fmt.Println(rsp, err)
}
```

View File

@@ -0,0 +1,21 @@
package example
import (
"fmt"
"os"
"go.m3o.com/email"
)
// Send an email by passing in from, to, subject, and a text or html body
func SendEmail() {
emailService := email.NewEmailService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emailService.Send(&email.SendRequest{
From: "Awesome Dot Com",
Subject: "Email verification",
TextBody: `Hi there,
Please verify your email by clicking this link: $micro_verification_link`,
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,22 @@
package main
import (
"fmt"
"os"
"go.m3o.com/email"
)
// Send an email by passing in from, to, subject, and a text or html body
func main() {
emailService := email.NewEmailService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emailService.Send(&email.SendRequest{
From: "Awesome Dot Com",
Subject: "Email verification",
TextBody: `Hi there,
Please verify your email by clicking this link: $micro_verification_link`,
})
fmt.Println(rsp, err)
}

121
examples/emoji/README.md Executable file
View File

@@ -0,0 +1,121 @@
# Emoji
An [m3o.com](https://m3o.com) API. For example usage see [m3o.com/Emoji/api](https://m3o.com/Emoji/api).
Endpoints:
## Print
Print text and renders the emojis with aliases e.g
let's grab a :beer: becomes let's grab a 🍺
[https://m3o.com/emoji/api#Print](https://m3o.com/emoji/api#Print)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/emoji"
)
// Print text and renders the emojis with aliases e.g
// let's grab a :beer: becomes let's grab a 🍺
func PrintTextIncludingEmoji() {
emojiService := emoji.NewEmojiService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emojiService.Print(&emoji.PrintRequest{
Text: "let's grab a :beer:",
})
fmt.Println(rsp, err)
}
```
## Send
Send an emoji to anyone via SMS. Messages are sent in the form '<message> Sent from <from>'
[https://m3o.com/emoji/api#Send](https://m3o.com/emoji/api#Send)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/emoji"
)
// Send an emoji to anyone via SMS. Messages are sent in the form '<message> Sent from <from>'
func SendAtextContainingAnEmojiToAnyoneViaSms() {
emojiService := emoji.NewEmojiService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emojiService.Send(&emoji.SendRequest{
From: "Alice",
Message: "let's grab a :beer:",
To: "+44782669123",
})
fmt.Println(rsp, err)
}
```
## Find
Find an emoji by its alias e.g :beer:
[https://m3o.com/emoji/api#Find](https://m3o.com/emoji/api#Find)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/emoji"
)
// Find an emoji by its alias e.g :beer:
func FindEmoji() {
emojiService := emoji.NewEmojiService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emojiService.Find(&emoji.FindRequest{
Alias: ":beer:",
})
fmt.Println(rsp, err)
}
```
## Flag
Get the flag for a country. Requires country code e.g GB for great britain
[https://m3o.com/emoji/api#Flag](https://m3o.com/emoji/api#Flag)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/emoji"
)
// Get the flag for a country. Requires country code e.g GB for great britain
func GetFlagByCountryCode() {
emojiService := emoji.NewEmojiService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emojiService.Flag(&emoji.FlagRequest{
})
fmt.Println(rsp, err)
}
```

View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/emoji"
)
// Find an emoji by its alias e.g :beer:
func FindEmoji() {
emojiService := emoji.NewEmojiService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emojiService.Find(&emoji.FindRequest{
Alias: ":beer:",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/emoji"
)
// Find an emoji by its alias e.g :beer:
func main() {
emojiService := emoji.NewEmojiService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emojiService.Find(&emoji.FindRequest{
Alias: ":beer:",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,15 @@
package example
import (
"fmt"
"os"
"go.m3o.com/emoji"
)
// Get the flag for a country. Requires country code e.g GB for great britain
func GetFlagByCountryCode() {
emojiService := emoji.NewEmojiService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emojiService.Flag(&emoji.FlagRequest{})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,16 @@
package main
import (
"fmt"
"os"
"go.m3o.com/emoji"
)
// Get the flag for a country. Requires country code e.g GB for great britain
func main() {
emojiService := emoji.NewEmojiService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emojiService.Flag(&emoji.FlagRequest{})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package example
import (
"fmt"
"os"
"go.m3o.com/emoji"
)
// Print text and renders the emojis with aliases e.g
// let's grab a :beer: becomes let's grab a 🍺
func PrintTextIncludingEmoji() {
emojiService := emoji.NewEmojiService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emojiService.Print(&emoji.PrintRequest{
Text: "let's grab a :beer:",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,19 @@
package main
import (
"fmt"
"os"
"go.m3o.com/emoji"
)
// Print text and renders the emojis with aliases e.g
// let's grab a :beer: becomes let's grab a 🍺
func main() {
emojiService := emoji.NewEmojiService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emojiService.Print(&emoji.PrintRequest{
Text: "let's grab a :beer:",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,19 @@
package example
import (
"fmt"
"os"
"go.m3o.com/emoji"
)
// Send an emoji to anyone via SMS. Messages are sent in the form '<message> Sent from <from>'
func SendAtextContainingAnEmojiToAnyoneViaSms() {
emojiService := emoji.NewEmojiService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emojiService.Send(&emoji.SendRequest{
From: "Alice",
Message: "let's grab a :beer:",
To: "+44782669123",
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,20 @@
package main
import (
"fmt"
"os"
"go.m3o.com/emoji"
)
// Send an emoji to anyone via SMS. Messages are sent in the form '<message> Sent from <from>'
func main() {
emojiService := emoji.NewEmojiService(os.Getenv("M3O_API_TOKEN"))
rsp, err := emojiService.Send(&emoji.SendRequest{
From: "Alice",
Message: "let's grab a :beer:",
To: "+44782669123",
})
fmt.Println(rsp, err)
}

127
examples/evchargers/README.md Executable file
View File

@@ -0,0 +1,127 @@
# Evchargers
An [m3o.com](https://m3o.com) API. For example usage see [m3o.com/Evchargers/api](https://m3o.com/Evchargers/api).
Endpoints:
## Search
Search by giving a coordinate and a max distance, or bounding box and optional filters
[https://m3o.com/evchargers/api#Search](https://m3o.com/evchargers/api#Search)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/evchargers"
)
// Search by giving a coordinate and a max distance, or bounding box and optional filters
func SearchByLocation() {
evchargersService := evchargers.NewEvchargersService(os.Getenv("M3O_API_TOKEN"))
rsp, err := evchargersService.Search(&evchargers.SearchRequest{
Distance: 2000,
Location: &evchargers.Coordinates{
Latitude: 51.53336351319885,
Longitude: -0.0252,
},
})
fmt.Println(rsp, err)
}
```
## Search
Search by giving a coordinate and a max distance, or bounding box and optional filters
[https://m3o.com/evchargers/api#Search](https://m3o.com/evchargers/api#Search)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/evchargers"
)
// Search by giving a coordinate and a max distance, or bounding box and optional filters
func SearchByBoundingBox() {
evchargersService := evchargers.NewEvchargersService(os.Getenv("M3O_API_TOKEN"))
rsp, err := evchargersService.Search(&evchargers.SearchRequest{
Box: &evchargers.BoundingBox{
},
})
fmt.Println(rsp, err)
}
```
## Search
Search by giving a coordinate and a max distance, or bounding box and optional filters
[https://m3o.com/evchargers/api#Search](https://m3o.com/evchargers/api#Search)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/evchargers"
)
// Search by giving a coordinate and a max distance, or bounding box and optional filters
func SearchWithFiltersFastChargersOnly() {
evchargersService := evchargers.NewEvchargersService(os.Getenv("M3O_API_TOKEN"))
rsp, err := evchargersService.Search(&evchargers.SearchRequest{
Distance: 2000,
Levels: []string{"3"},
Location: &evchargers.Coordinates{
Latitude: 51.53336351319885,
Longitude: -0.0252,
},
})
fmt.Println(rsp, err)
}
```
## ReferenceData
Retrieve reference data as used by this API and in conjunction with the Search endpoint
[https://m3o.com/evchargers/api#ReferenceData](https://m3o.com/evchargers/api#ReferenceData)
```go
package example
import(
"fmt"
"os"
"go.m3o.com/evchargers"
)
// Retrieve reference data as used by this API and in conjunction with the Search endpoint
func GetReferenceData() {
evchargersService := evchargers.NewEvchargersService(os.Getenv("M3O_API_TOKEN"))
rsp, err := evchargersService.ReferenceData(&evchargers.ReferenceDataRequest{
})
fmt.Println(rsp, err)
}
```

View File

@@ -0,0 +1,15 @@
package example
import (
"fmt"
"os"
"go.m3o.com/evchargers"
)
// Retrieve reference data as used by this API and in conjunction with the Search endpoint
func GetReferenceData() {
evchargersService := evchargers.NewEvchargersService(os.Getenv("M3O_API_TOKEN"))
rsp, err := evchargersService.ReferenceData(&evchargers.ReferenceDataRequest{})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,16 @@
package main
import (
"fmt"
"os"
"go.m3o.com/evchargers"
)
// Retrieve reference data as used by this API and in conjunction with the Search endpoint
func main() {
evchargersService := evchargers.NewEvchargersService(os.Getenv("M3O_API_TOKEN"))
rsp, err := evchargersService.ReferenceData(&evchargers.ReferenceDataRequest{})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,17 @@
package example
import (
"fmt"
"os"
"go.m3o.com/evchargers"
)
// Search by giving a coordinate and a max distance, or bounding box and optional filters
func SearchByBoundingBox() {
evchargersService := evchargers.NewEvchargersService(os.Getenv("M3O_API_TOKEN"))
rsp, err := evchargersService.Search(&evchargers.SearchRequest{
Box: &evchargers.BoundingBox{},
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"go.m3o.com/evchargers"
)
// Search by giving a coordinate and a max distance, or bounding box and optional filters
func main() {
evchargersService := evchargers.NewEvchargersService(os.Getenv("M3O_API_TOKEN"))
rsp, err := evchargersService.Search(&evchargers.SearchRequest{
Box: &evchargers.BoundingBox{},
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,21 @@
package example
import (
"fmt"
"os"
"go.m3o.com/evchargers"
)
// Search by giving a coordinate and a max distance, or bounding box and optional filters
func SearchByLocation() {
evchargersService := evchargers.NewEvchargersService(os.Getenv("M3O_API_TOKEN"))
rsp, err := evchargersService.Search(&evchargers.SearchRequest{
Distance: 2000,
Location: &evchargers.Coordinates{
Latitude: 51.53336351319885,
Longitude: -0.0252,
},
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,22 @@
package main
import (
"fmt"
"os"
"go.m3o.com/evchargers"
)
// Search by giving a coordinate and a max distance, or bounding box and optional filters
func main() {
evchargersService := evchargers.NewEvchargersService(os.Getenv("M3O_API_TOKEN"))
rsp, err := evchargersService.Search(&evchargers.SearchRequest{
Distance: 2000,
Location: &evchargers.Coordinates{
Latitude: 51.53336351319885,
Longitude: -0.0252,
},
})
fmt.Println(rsp, err)
}

View File

@@ -0,0 +1,22 @@
package example
import (
"fmt"
"os"
"go.m3o.com/evchargers"
)
// Search by giving a coordinate and a max distance, or bounding box and optional filters
func SearchWithFiltersFastChargersOnly() {
evchargersService := evchargers.NewEvchargersService(os.Getenv("M3O_API_TOKEN"))
rsp, err := evchargersService.Search(&evchargers.SearchRequest{
Distance: 2000,
Levels: []string{"3"},
Location: &evchargers.Coordinates{
Latitude: 51.53336351319885,
Longitude: -0.0252,
},
})
fmt.Println(rsp, err)
}

Some files were not shown because too many files have changed in this diff Show More