chatrix 1.0.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.editorconfig +12 -0
- data/.gitignore +167 -0
- data/.rspec +3 -0
- data/.travis.yml +8 -0
- data/.yardopts +5 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +63 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/chatrix.gemspec +34 -0
- data/lib/chatrix.rb +7 -0
- data/lib/chatrix/errors.rb +54 -0
- data/lib/chatrix/matrix.rb +730 -0
- data/lib/chatrix/version.rb +4 -0
- metadata +173 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f4d840405e59e950232bf4a82a906c7395d3c581
|
4
|
+
data.tar.gz: 26d630e954f5cc66b8bdd9dd5f01132ef6ca84af
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bd3aa274eb0b3da53e24f8cfb95b354025513a421fd094172a912791de0962e171f9817906bb811bdc125047f415173c78a612ca7f9179bc1fc34ed710cf9e51
|
7
|
+
data.tar.gz: 61275fb3232b31c24b3e0d215107655ecbd65d4836b04d97b3d8c6a79c7896100428f59a509eb1e27c863597c08dc2455e265e75d53b7543b67ef48cecb39306
|
data/.editorconfig
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# Created by https://www.gitignore.io/api/ruby,git,windows,linux,osx,vim,sublimetext
|
2
|
+
|
3
|
+
### Ruby ###
|
4
|
+
*.gem
|
5
|
+
*.rbc
|
6
|
+
/.config
|
7
|
+
/coverage/
|
8
|
+
/InstalledFiles
|
9
|
+
/pkg/
|
10
|
+
/spec/reports/
|
11
|
+
/spec/examples.txt
|
12
|
+
/test/tmp/
|
13
|
+
/test/version_tmp/
|
14
|
+
/tmp/
|
15
|
+
|
16
|
+
# Used by dotenv library to load environment variables.
|
17
|
+
# .env
|
18
|
+
|
19
|
+
## Specific to RubyMotion:
|
20
|
+
.dat*
|
21
|
+
.repl_history
|
22
|
+
build/
|
23
|
+
*.bridgesupport
|
24
|
+
build-iPhoneOS/
|
25
|
+
build-iPhoneSimulator/
|
26
|
+
|
27
|
+
## Specific to RubyMotion (use of CocoaPods):
|
28
|
+
#
|
29
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
30
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
31
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
32
|
+
#
|
33
|
+
# vendor/Pods/
|
34
|
+
|
35
|
+
## Documentation cache and generated files:
|
36
|
+
/.yardoc/
|
37
|
+
/_yardoc/
|
38
|
+
/doc/
|
39
|
+
/rdoc/
|
40
|
+
|
41
|
+
## Environment normalization:
|
42
|
+
/.bundle/
|
43
|
+
/vendor/bundle
|
44
|
+
/lib/bundler/man/
|
45
|
+
|
46
|
+
# for a library or gem, you might want to ignore these files since the code is
|
47
|
+
# intended to run in multiple environments; otherwise, check them in:
|
48
|
+
Gemfile.lock
|
49
|
+
.ruby-version
|
50
|
+
.ruby-gemset
|
51
|
+
|
52
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
53
|
+
.rvmrc
|
54
|
+
|
55
|
+
|
56
|
+
### Git ###
|
57
|
+
*.orig
|
58
|
+
|
59
|
+
|
60
|
+
### Windows ###
|
61
|
+
# Windows image file caches
|
62
|
+
Thumbs.db
|
63
|
+
ehthumbs.db
|
64
|
+
|
65
|
+
# Folder config file
|
66
|
+
Desktop.ini
|
67
|
+
|
68
|
+
# Recycle Bin used on file shares
|
69
|
+
$RECYCLE.BIN/
|
70
|
+
|
71
|
+
# Windows Installer files
|
72
|
+
*.cab
|
73
|
+
*.msi
|
74
|
+
*.msm
|
75
|
+
*.msp
|
76
|
+
|
77
|
+
# Windows shortcuts
|
78
|
+
*.lnk
|
79
|
+
|
80
|
+
|
81
|
+
### Linux ###
|
82
|
+
*~
|
83
|
+
|
84
|
+
# temporary files which can be created if a process still has a handle open of a deleted file
|
85
|
+
.fuse_hidden*
|
86
|
+
|
87
|
+
# KDE directory preferences
|
88
|
+
.directory
|
89
|
+
|
90
|
+
# Linux trash folder which might appear on any partition or disk
|
91
|
+
.Trash-*
|
92
|
+
|
93
|
+
|
94
|
+
### OSX ###
|
95
|
+
*.DS_Store
|
96
|
+
.AppleDouble
|
97
|
+
.LSOverride
|
98
|
+
|
99
|
+
# Icon must end with two \r
|
100
|
+
Icon
|
101
|
+
|
102
|
+
|
103
|
+
# Thumbnails
|
104
|
+
._*
|
105
|
+
|
106
|
+
# Files that might appear in the root of a volume
|
107
|
+
.DocumentRevisions-V100
|
108
|
+
.fseventsd
|
109
|
+
.Spotlight-V100
|
110
|
+
.TemporaryItems
|
111
|
+
.Trashes
|
112
|
+
.VolumeIcon.icns
|
113
|
+
.com.apple.timemachine.donotpresent
|
114
|
+
|
115
|
+
# Directories potentially created on remote AFP share
|
116
|
+
.AppleDB
|
117
|
+
.AppleDesktop
|
118
|
+
Network Trash Folder
|
119
|
+
Temporary Items
|
120
|
+
.apdisk
|
121
|
+
|
122
|
+
|
123
|
+
### Vim ###
|
124
|
+
# swap
|
125
|
+
[._]*.s[a-w][a-z]
|
126
|
+
[._]s[a-w][a-z]
|
127
|
+
# session
|
128
|
+
Session.vim
|
129
|
+
# temporary
|
130
|
+
.netrwhist
|
131
|
+
*~
|
132
|
+
# auto-generated tag files
|
133
|
+
tags
|
134
|
+
|
135
|
+
|
136
|
+
### SublimeText ###
|
137
|
+
# cache files for sublime text
|
138
|
+
*.tmlanguage.cache
|
139
|
+
*.tmPreferences.cache
|
140
|
+
*.stTheme.cache
|
141
|
+
|
142
|
+
# workspace files are user-specific
|
143
|
+
*.sublime-workspace
|
144
|
+
|
145
|
+
# project files should be checked into the repository, unless a significant
|
146
|
+
# proportion of contributors will probably not be using SublimeText
|
147
|
+
# *.sublime-project
|
148
|
+
|
149
|
+
# sftp configuration file
|
150
|
+
sftp-config.json
|
151
|
+
|
152
|
+
# Package control specific files
|
153
|
+
Package Control.last-run
|
154
|
+
Package Control.ca-list
|
155
|
+
Package Control.ca-bundle
|
156
|
+
Package Control.system-ca-bundle
|
157
|
+
Package Control.cache/
|
158
|
+
Package Control.ca-certs/
|
159
|
+
bh_unicode_properties.cache
|
160
|
+
|
161
|
+
# Sublime-github package stores a github token in this file
|
162
|
+
# https://packagecontrol.io/packages/sublime-github
|
163
|
+
GitHub.sublime-settings
|
164
|
+
|
165
|
+
### Custom rules ###
|
166
|
+
# Ignore access token file
|
167
|
+
access_token.txt
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 by Adam Hellberg.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
chatrix
|
2
|
+
=======
|
3
|
+
|
4
|
+
A Ruby implementation of the [Matrix][matrix] API.
|
5
|
+
|
6
|
+
## License
|
7
|
+
|
8
|
+
Copyright (c) 2016 by Adam Hellberg.
|
9
|
+
|
10
|
+
chatrix is licensed under the [MIT License][license-url], see the file
|
11
|
+
`LICENSE` for more information.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'chatrix'
|
19
|
+
```
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install chatrix
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
This implementation is currently very basic and exposes all the endpoints
|
32
|
+
in the `Matrix` class. Example usage:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
# Uses the standard matrix.org homeserver
|
36
|
+
api = Chatrix::Matrix.new 'my secret token'
|
37
|
+
|
38
|
+
# Join may raise ForbiddenError if client does not have permission
|
39
|
+
# to join the room
|
40
|
+
if id = api.join '#myroom:myserver.org'
|
41
|
+
api.send_message id, 'Hello everyone!'
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
Currently there is no asynchronous calls or built-in handling of
|
46
|
+
rate-limiting.
|
47
|
+
|
48
|
+
## Development
|
49
|
+
|
50
|
+
After checking out the repo, run `bin/setup` to install dependencies.
|
51
|
+
Then, run `rake spec` to run the tests. You can also run `bin/console`
|
52
|
+
for an interactive prompt that will allow you to experiment.
|
53
|
+
|
54
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
55
|
+
|
56
|
+
## Contributing
|
57
|
+
|
58
|
+
Bug reports and pull requests are welcome on [GitHub][issues].
|
59
|
+
|
60
|
+
[project]: https://github.com/Sharparam/chatrix
|
61
|
+
[issues]: https://github.com/Sharparam/chatrix/issues
|
62
|
+
[matrix]: http://matrix.org
|
63
|
+
[license-url]: http://opensource.org/licenses/MIT
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'chatrix'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'pry'
|
14
|
+
Pry.start
|
data/bin/setup
ADDED
data/chatrix.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'chatrix/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'chatrix'
|
8
|
+
spec.version = Chatrix::VERSION
|
9
|
+
spec.authors = ['Adam Hellberg']
|
10
|
+
spec.email = ['sharparam@sharparam.com']
|
11
|
+
|
12
|
+
spec.summary = 'Ruby implementation of the Matrix API'
|
13
|
+
# spec.description = %q{}
|
14
|
+
spec.homepage = 'https://github.com/Sharparam/chatrix'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
|
21
|
+
spec.bindir = 'exe'
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.add_runtime_dependency 'httparty', '~> 0.13'
|
26
|
+
|
27
|
+
spec.add_development_dependency 'bundler', '~> 1.12'
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
30
|
+
spec.add_development_dependency 'pry', '~> 0.10'
|
31
|
+
spec.add_development_dependency 'yard', '~> 0.8'
|
32
|
+
spec.add_development_dependency 'redcarpet', '~> 3.3'
|
33
|
+
spec.add_development_dependency 'rubocop', '~> 0.40.0'
|
34
|
+
end
|
data/lib/chatrix.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
module Chatrix
|
2
|
+
# Generic faults from the library.
|
3
|
+
class ChatrixError < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
# Errors that stem from an API call.
|
7
|
+
class ApiError < ChatrixError
|
8
|
+
end
|
9
|
+
|
10
|
+
# Error raised when a request is badly formatted.
|
11
|
+
class RequestError < ApiError
|
12
|
+
attr_reader :code, :api_message
|
13
|
+
|
14
|
+
def initialize(error)
|
15
|
+
@code = error['errcode']
|
16
|
+
@api_message = error['error']
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Raised when a resource is requested that the user does not have access to.
|
21
|
+
class ForbiddenError < ApiError
|
22
|
+
end
|
23
|
+
|
24
|
+
# Raised when a resource is not found.
|
25
|
+
class NotFoundError < ApiError
|
26
|
+
end
|
27
|
+
|
28
|
+
# Raised when a user is not found.
|
29
|
+
class UserNotFoundError < NotFoundError
|
30
|
+
attr_reader :username
|
31
|
+
|
32
|
+
def initialize(username)
|
33
|
+
@username = username
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Raised when a user's avatar is not found.
|
38
|
+
class AvatarNotFoundError < NotFoundError
|
39
|
+
attr_reader :username
|
40
|
+
|
41
|
+
def initialize(username)
|
42
|
+
@username = username
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Raised when a room is not found.
|
47
|
+
class RoomNotFoundError < NotFoundError
|
48
|
+
attr_reader :room
|
49
|
+
|
50
|
+
def initialize(room)
|
51
|
+
@room = room
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,730 @@
|
|
1
|
+
require 'chatrix/errors'
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
|
5
|
+
module Chatrix
|
6
|
+
# Provides an interface to the Matrix API on a homeserver.
|
7
|
+
#
|
8
|
+
# Detailed information about the data structures is not included here and
|
9
|
+
# can be found on the
|
10
|
+
# {http://matrix.org/docs/api/client-server Matrix API page}.
|
11
|
+
#
|
12
|
+
# @note Any of the methods may raise the errors listed in {#parse_response}.
|
13
|
+
# Consider this when calling the methods.
|
14
|
+
# @note Endpoints that require a room ID in the official API can be passed
|
15
|
+
# a room alias in this implementation, the room ID will be automatically
|
16
|
+
# looked up from the homeserver.
|
17
|
+
#
|
18
|
+
# @todo Try to extract functionality to make this class smaller.
|
19
|
+
#
|
20
|
+
# rubocop:disable ClassLength
|
21
|
+
class Matrix
|
22
|
+
include HTTParty
|
23
|
+
|
24
|
+
headers('User-Agent' => "chatrix/#{Chatrix::VERSION}",
|
25
|
+
'Content-Type' => 'application/json',
|
26
|
+
'Accept' => 'application/json')
|
27
|
+
|
28
|
+
# Maps HTTP methods to their respective HTTParty method.
|
29
|
+
METHODS = {
|
30
|
+
get: -> (path, options, &block) { get path, options, &block },
|
31
|
+
put: -> (path, options, &block) { put path, options, &block },
|
32
|
+
post: -> (path, options, &block) { post path, options, &block },
|
33
|
+
delete: -> (path, options, &block) { delete path, options, &block }
|
34
|
+
}.freeze
|
35
|
+
|
36
|
+
# Default homeserver used if none is specified.
|
37
|
+
DEFAULT_HOMESERVER = 'https://matrix.org'.freeze
|
38
|
+
|
39
|
+
# API path used.
|
40
|
+
API_PATH = '/_matrix/client/r0'.freeze
|
41
|
+
|
42
|
+
# @!attribute access_token
|
43
|
+
# @return [String] The access token used when performing requests
|
44
|
+
# to the homeserver.
|
45
|
+
attr_accessor :access_token
|
46
|
+
|
47
|
+
# @!attribute [r] homeserver
|
48
|
+
# @return [String] The homeserver for this API object.
|
49
|
+
attr_reader :homeserver
|
50
|
+
|
51
|
+
# Initializes a new instance of Matrix.
|
52
|
+
#
|
53
|
+
# @param token [String] The access token to use.
|
54
|
+
# @param homeserver [String] The homeserver to make requests to.
|
55
|
+
def initialize(token = nil, homeserver = DEFAULT_HOMESERVER)
|
56
|
+
@homeserver = homeserver
|
57
|
+
@base_uri = @homeserver + API_PATH
|
58
|
+
@transaction_id = 0
|
59
|
+
@access_token = token
|
60
|
+
end
|
61
|
+
|
62
|
+
# Gets third-party IDs associated with the current account.
|
63
|
+
#
|
64
|
+
# @return [Array] A list of 3rd party IDs.
|
65
|
+
def threepids
|
66
|
+
make_request(:get, '/account/3pid')['threepids']
|
67
|
+
end
|
68
|
+
|
69
|
+
# Gets information about a specific user.
|
70
|
+
#
|
71
|
+
# @param user [String] The user to query (`@user:host.tld`).
|
72
|
+
# @return [Hash] The user information.
|
73
|
+
# @raise [UserNotFoundError] If the user could not be found.
|
74
|
+
#
|
75
|
+
# @example Print a user's display name
|
76
|
+
# puts get_user('@foo:matrix.org')['displayname']
|
77
|
+
def get_user(user)
|
78
|
+
make_request(:get, "/profile/#{user}").parsed_response
|
79
|
+
rescue NotFoundError
|
80
|
+
raise UserNotFoundError.new(user), 'The specified user could not be found'
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get the URL to a user's avatar (an `mxp://` URL).
|
84
|
+
#
|
85
|
+
# @param (see #get_user)
|
86
|
+
# @return [String] The avatar URL.
|
87
|
+
# @raise [AvatarNotFoundError] If the avatar or user could not be found.
|
88
|
+
def get_avatar(user)
|
89
|
+
make_request(:get, "/profile/#{user}/avatar_url")['avatar_url']
|
90
|
+
rescue NotFoundError
|
91
|
+
raise AvatarNotFoundError.new(user), 'Avatar or user could not be found'
|
92
|
+
end
|
93
|
+
|
94
|
+
# Get a user's display name (**not** username).
|
95
|
+
#
|
96
|
+
# @param (see #get_user)
|
97
|
+
# @raise (see #get_user)
|
98
|
+
def get_displayname(user)
|
99
|
+
make_request(:get, "/profile/#{user}/displayname")['displayname']
|
100
|
+
rescue NotFoundError
|
101
|
+
raise UserNotFoundError.new(user), 'The specified user could not be found'
|
102
|
+
end
|
103
|
+
|
104
|
+
# Sets a new display name for a user.
|
105
|
+
#
|
106
|
+
# @note Can only be used on the user who possesses the
|
107
|
+
# {#access_token access_token} currently in use.
|
108
|
+
#
|
109
|
+
# @param user [String] The user to modify (`@user:host.tld`).
|
110
|
+
# @param displayname [String] The new displayname to set.
|
111
|
+
# @return [Boolean] `true` if the new display name was successfully set,
|
112
|
+
# otherwise `false`.
|
113
|
+
def set_displayname(user, displayname)
|
114
|
+
make_request(
|
115
|
+
:put,
|
116
|
+
"/profile/#{user}/displayname",
|
117
|
+
content: {
|
118
|
+
displayname: displayname
|
119
|
+
}
|
120
|
+
).code == 200
|
121
|
+
end
|
122
|
+
|
123
|
+
# Get tags that a specific user has set on a room.
|
124
|
+
#
|
125
|
+
# @param user [String] The user whose settings to retrieve
|
126
|
+
# (`@user:host.tld`).
|
127
|
+
# @param room [String] The room to get tags from (ID or alias).
|
128
|
+
# @return [Hash{String=>Hash}] A hash with tag data. The tag name is
|
129
|
+
# the key and any additional metadata is contained in the Hash value.
|
130
|
+
def get_user_room_tags(user, room)
|
131
|
+
room = get_room_id room if room.start_with? '#'
|
132
|
+
make_request(:get, "/user/#{user}/rooms/#{room}/tags")['tags']
|
133
|
+
end
|
134
|
+
|
135
|
+
# Get information about a room alias.
|
136
|
+
#
|
137
|
+
# This can be used to get the room ID that an alias points to.
|
138
|
+
#
|
139
|
+
# @param room_alias [String] The room alias to query, this **must** be an
|
140
|
+
# alias and not an ID.
|
141
|
+
# @return [Hash] Returns information about the alias in a Hash.
|
142
|
+
#
|
143
|
+
# @see #get_room_id #get_room_id is an example of how this method could be
|
144
|
+
# used to get a room's ID.
|
145
|
+
def get_room_alias_info(room_alias)
|
146
|
+
make_request(:get, "/directory/room/#{room_alias}").parsed_response
|
147
|
+
rescue NotFoundError
|
148
|
+
raise RoomNotFoundError.new(room_alias),
|
149
|
+
'The specified room alias could not be found'
|
150
|
+
end
|
151
|
+
|
152
|
+
# Get a room's ID from its alias.
|
153
|
+
#
|
154
|
+
# @param room_alias [String] The room alias to query.
|
155
|
+
# @return [String] The actual room ID for the room.
|
156
|
+
def get_room_id(room_alias)
|
157
|
+
get_room_alias_info(room_alias)['room_id']
|
158
|
+
end
|
159
|
+
|
160
|
+
# Gets context for an event in a room.
|
161
|
+
#
|
162
|
+
# The method will return events that happened before and after the
|
163
|
+
# specified event.
|
164
|
+
#
|
165
|
+
# @param room [String] The room to query.
|
166
|
+
# @param event [String] The event to get context for.
|
167
|
+
# @param limit [Fixnum] Maximum number of events to retrieve.
|
168
|
+
# @return [Hash] The returned hash contains information about the events
|
169
|
+
# happening before and after the specified event, as well as start and
|
170
|
+
# end timestamps and state information for the event.
|
171
|
+
def get_event_context(room, event, limit = 10)
|
172
|
+
room = get_room_id room if room.start_with? '#'
|
173
|
+
make_request(
|
174
|
+
:get,
|
175
|
+
"/rooms/#{room}/context/#{event}",
|
176
|
+
params: { limit: limit }
|
177
|
+
).parsed_response
|
178
|
+
end
|
179
|
+
|
180
|
+
# Get the members of a room.
|
181
|
+
#
|
182
|
+
# @param room [String] The room to query.
|
183
|
+
# @return [Array] An array of users that are in this room.
|
184
|
+
def get_room_members(room)
|
185
|
+
room = get_room_id room if room.start_with? '#'
|
186
|
+
make_request(:get, "/rooms/#{room}/members")['chunk']
|
187
|
+
end
|
188
|
+
|
189
|
+
# Get a list of messages from a room.
|
190
|
+
#
|
191
|
+
# @param room [String] The room to get messages from.
|
192
|
+
# @param from [String] Token to return events from.
|
193
|
+
# @param direction ['b', 'f'] Direction to return events from.
|
194
|
+
# @param limit [Fixnum] Maximum number of events to return.
|
195
|
+
# @return [Hash] A hash containing the messages, as well as `start` and
|
196
|
+
# `end` tokens for pagination.
|
197
|
+
def get_room_messages(room, from, direction, limit = 10)
|
198
|
+
room = get_room_id room if room.start_with? '#'
|
199
|
+
make_request(
|
200
|
+
:get,
|
201
|
+
"/rooms/#{room}/messages",
|
202
|
+
params: {
|
203
|
+
from: from,
|
204
|
+
dir: direction,
|
205
|
+
limit: limit
|
206
|
+
}
|
207
|
+
).parsed_response
|
208
|
+
end
|
209
|
+
|
210
|
+
# Sends a message object to a room.
|
211
|
+
#
|
212
|
+
# @param room [String] The room to send to.
|
213
|
+
# @param content [Hash] The message content to send.
|
214
|
+
# @param type [String] The type of message to send.
|
215
|
+
# @return [String] The event ID of the sent message is returned.
|
216
|
+
# @see #send_message_type
|
217
|
+
# @see #send_message
|
218
|
+
# @see #send_emote
|
219
|
+
# @see #send_notice
|
220
|
+
# @see #send_html
|
221
|
+
def send_message_raw(room, content, type = 'm.room.message')
|
222
|
+
room = get_room_id room if room.start_with? '#'
|
223
|
+
@transaction_id += 1
|
224
|
+
make_request(
|
225
|
+
:put,
|
226
|
+
"/rooms/#{room}/send/#{type}/#{@transaction_id}",
|
227
|
+
content: content
|
228
|
+
)['event_id']
|
229
|
+
end
|
230
|
+
|
231
|
+
# A helper method to send a simple message construct.
|
232
|
+
#
|
233
|
+
# @param room [String] The room to send the message to.
|
234
|
+
# @param content [String] The message to send.
|
235
|
+
# @param type [String] The type of message this is.
|
236
|
+
# @return (see #send_message_raw)
|
237
|
+
# @see #send_message
|
238
|
+
# @see #send_notice
|
239
|
+
# @see #send_emote
|
240
|
+
# @see #send_html
|
241
|
+
def send_message_type(room, content, type = 'm.text')
|
242
|
+
send_message_raw room, msgtype: type, body: content
|
243
|
+
end
|
244
|
+
|
245
|
+
# Sends a plaintext message to a room.
|
246
|
+
#
|
247
|
+
# @param room [String] The room to send to.
|
248
|
+
# @param content [String] The message to send.
|
249
|
+
# @return (see #send_message_raw)
|
250
|
+
#
|
251
|
+
# @example Sending a simple message
|
252
|
+
# send_message('#party:matrix.org', 'Hello everyone!')
|
253
|
+
def send_message(room, content)
|
254
|
+
send_message_type room, content
|
255
|
+
end
|
256
|
+
|
257
|
+
# Sends a notice message to a room.
|
258
|
+
#
|
259
|
+
# @param room [String] The room to send to.
|
260
|
+
# @param content [String] The message to send.
|
261
|
+
# @return (see #send_message_raw)
|
262
|
+
#
|
263
|
+
# @example Sending a notice
|
264
|
+
# send_notice('#stuff:matrix.org', 'This is a notice')
|
265
|
+
def send_notice(room, content)
|
266
|
+
send_message_type room, content, 'm.notice'
|
267
|
+
end
|
268
|
+
|
269
|
+
# Sends an emote to a room.
|
270
|
+
#
|
271
|
+
# `/me <message here>`
|
272
|
+
#
|
273
|
+
# @param room [String] The room to send to.
|
274
|
+
# @param content [String] The emote to send.
|
275
|
+
# @return (see #send_message_raw)
|
276
|
+
#
|
277
|
+
# @example Sending an emote
|
278
|
+
# # Will show up as: "* <user> is having fun"
|
279
|
+
# send_emote('#party:matrix.org', 'is having fun')
|
280
|
+
def send_emote(room, content)
|
281
|
+
send_message_type room, content, 'm.emote'
|
282
|
+
end
|
283
|
+
|
284
|
+
# Sends a message formatted using HTML markup.
|
285
|
+
#
|
286
|
+
# The `body` field in the content will have the HTML stripped out, and is
|
287
|
+
# usually presented in clients that don't support the formatting.
|
288
|
+
#
|
289
|
+
# The `formatted_body` field in the content will contain the actual HTML
|
290
|
+
# formatted message (as passed to the `html` parameter).
|
291
|
+
#
|
292
|
+
# @param room [String] The room to send to.
|
293
|
+
# @param html [String] The HTML formatted text to send.
|
294
|
+
# @return (see #send_message_raw)
|
295
|
+
#
|
296
|
+
# @example Sending an HTML message
|
297
|
+
# send_html('#html:matrix.org', '<strong>Hello</strong> <em>world</em>!')
|
298
|
+
def send_html(room, html)
|
299
|
+
send_message_raw(
|
300
|
+
room,
|
301
|
+
msgtype: 'm.text',
|
302
|
+
format: 'org.matrix.custom.html',
|
303
|
+
body: html.gsub(%r{</?[^>]*?>}, ''), # TODO: Make this better
|
304
|
+
formatted_body: html
|
305
|
+
)
|
306
|
+
end
|
307
|
+
|
308
|
+
# @overload get_room_state(room)
|
309
|
+
# Get state events for the current state of a room.
|
310
|
+
# @param room [String] The room to get events for.
|
311
|
+
# @return [Array] An array with state events for the room.
|
312
|
+
# @overload get_room_state(room, type)
|
313
|
+
# Get the contents of a specific kind of state in the room.
|
314
|
+
# @param room [String] The room to get the data from.
|
315
|
+
# @param type [String] The type of state to get.
|
316
|
+
# @return [Hash] Information about the state type.
|
317
|
+
# @overload get_room_state(room, type, key)
|
318
|
+
# Get the contents of a specific kind of state including only the
|
319
|
+
# specified key in the result.
|
320
|
+
# @param room [String] The room to get the data from.
|
321
|
+
# @param type [String] The type of state to get.
|
322
|
+
# @param key [String] The key of the state to look up.
|
323
|
+
# @return [Hash] Information about the requested state.
|
324
|
+
def get_room_state(room, type = nil, key = nil)
|
325
|
+
room = get_room_id room if room.start_with? '#'
|
326
|
+
|
327
|
+
if type && key
|
328
|
+
make_request(
|
329
|
+
:get,
|
330
|
+
"/rooms/#{room}/state/#{type}/#{key}"
|
331
|
+
).parsed_response
|
332
|
+
elsif type
|
333
|
+
make_request(:get, "/rooms/#{room}/state/#{type}").parsed_response
|
334
|
+
else
|
335
|
+
make_request(:get, "/rooms/#{room}/state").parsed_response
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
# Sends a message to the server informing it about a user having started
|
340
|
+
# or stopped typing.
|
341
|
+
#
|
342
|
+
# @param room [String] The affected room.
|
343
|
+
# @param user [String] The user that started or stopped typing.
|
344
|
+
# @param typing [Boolean] Whether the user is typing.
|
345
|
+
# @param duration [Fixnum] How long the user will be typing for
|
346
|
+
# (in milliseconds).
|
347
|
+
# @return [Boolean] `true` if the message sent successfully, otherwise
|
348
|
+
# `false`.
|
349
|
+
def send_typing(room, user, typing = true, duration = 30_000)
|
350
|
+
room = get_room_id room if room.start_with? '#'
|
351
|
+
|
352
|
+
content = { typingState: { typing: typing, timeout: duration } }
|
353
|
+
|
354
|
+
make_request(
|
355
|
+
:put,
|
356
|
+
"/rooms/#{room}/typing/#{user}",
|
357
|
+
content: content
|
358
|
+
).code == 200
|
359
|
+
end
|
360
|
+
|
361
|
+
# Synchronize with the latest state on the server.
|
362
|
+
#
|
363
|
+
# For initial sync, call this method with the `since` parameter
|
364
|
+
# set to `nil`.
|
365
|
+
#
|
366
|
+
# @param filter [String,Hash] The ID of a filter to use, or provided
|
367
|
+
# directly as a hash.
|
368
|
+
# @param since [String,nil] A point in time to continue sync from.
|
369
|
+
# Will retrieve a snapshot of the state if not set, which will also
|
370
|
+
# provide a `next_batch` value to use for `since` in the next call.
|
371
|
+
# @param full_state [Boolean] If `true`, all state events will be returned
|
372
|
+
# for all rooms the user is a member of.
|
373
|
+
# @param set_presence [Boolean] If `true`, the user performing this request
|
374
|
+
# will have their presence updated to show them as being online.
|
375
|
+
# @param timeout [Fixnum] Maximum time (in milliseconds) to wait before
|
376
|
+
# the request is aborted.
|
377
|
+
# @return [Hash] The initial snapshot of the state (if no `since` value
|
378
|
+
# was provided), or a delta to use for updating state.
|
379
|
+
def sync(filter: nil, since: nil, full_state: false,
|
380
|
+
set_presence: true, timeout: 30_000)
|
381
|
+
options = { full_state: full_state }
|
382
|
+
|
383
|
+
options[:since] = since if since
|
384
|
+
options[:set_presence] = 'offline' unless set_presence
|
385
|
+
options[:timeout] = timeout if timeout
|
386
|
+
|
387
|
+
if filter.is_a? Integer
|
388
|
+
options[:filter] = filter
|
389
|
+
elsif filter.is_a? Hash
|
390
|
+
options[:filter] = URI.encode filter.to_json
|
391
|
+
end
|
392
|
+
|
393
|
+
make_request(:get, '/sync', params: options).parsed_response
|
394
|
+
end
|
395
|
+
|
396
|
+
# Joins a room on the homeserver.
|
397
|
+
#
|
398
|
+
# @param room [String] The room to join.
|
399
|
+
# @param third_party_signed [Hash,nil] If provided, the homeserver must
|
400
|
+
# verify that it matches a pending `m.room.third_party_invite` event in
|
401
|
+
# the room, and perform key validity checking if required by the event.
|
402
|
+
# @return [String] The ID of the room that was joined is returned.
|
403
|
+
def join(room, third_party_signed = nil)
|
404
|
+
if third_party_signed
|
405
|
+
make_request(
|
406
|
+
:post,
|
407
|
+
"/join/#{room}",
|
408
|
+
content: { third_party_signed: third_party_signed }
|
409
|
+
)['room_id']
|
410
|
+
else
|
411
|
+
make_request(:post, "/join/#{room}")['room_id']
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
# Kicks and bans a user from a room.
|
416
|
+
#
|
417
|
+
# @param room [String] The room to ban the user from.
|
418
|
+
# @param user [String] The user to ban.
|
419
|
+
# @param reason [String] Reason why the ban was made.
|
420
|
+
# @return [Boolean] `true` if the ban was carried out successfully,
|
421
|
+
# otherwise `false`.
|
422
|
+
#
|
423
|
+
# @example Banning a spammer
|
424
|
+
# ban('#haven:matrix.org', '@spammer:spam.com', 'Spamming the room')
|
425
|
+
def ban(room, user, reason)
|
426
|
+
room = get_room_id room if room.start_with? '#'
|
427
|
+
make_request(
|
428
|
+
:post,
|
429
|
+
"/rooms/#{room}/ban",
|
430
|
+
content: { reason: reason, user_id: user }
|
431
|
+
).code == 200
|
432
|
+
end
|
433
|
+
|
434
|
+
# Forgets about a room.
|
435
|
+
#
|
436
|
+
# @param room [String] The room to forget about.
|
437
|
+
# @return [Boolean] `true` if the room was forgotten successfully,
|
438
|
+
# otherwise `false`.
|
439
|
+
def forget(room)
|
440
|
+
room = get_room_id room if room.start_with? '#'
|
441
|
+
make_request(:post, "/rooms/#{room}/forget").code == 200
|
442
|
+
end
|
443
|
+
|
444
|
+
# Kicks a user from a room.
|
445
|
+
#
|
446
|
+
# This does not ban the user, they can rejoin unless the room is
|
447
|
+
# invite-only, in which case they need a new invite to join back.
|
448
|
+
#
|
449
|
+
# @param room [String] The room to kick the user from.
|
450
|
+
# @param user [String] The user to kick.
|
451
|
+
# @param reason [String] The reason for the kick.
|
452
|
+
# @return [Boolean] `true` if the user was successfully kicked,
|
453
|
+
# otherwise `false`.
|
454
|
+
#
|
455
|
+
# @example Kicking an annoying user
|
456
|
+
# kick('#fun:matrix.org', '@anon:4chan.org', 'Bad cropping')
|
457
|
+
def kick(room, user, reason)
|
458
|
+
room = get_room_id room if room.start_with? '#'
|
459
|
+
make_request(
|
460
|
+
:post,
|
461
|
+
"/rooms/#{room}/kick",
|
462
|
+
content: { reason: reason, user_id: user }
|
463
|
+
).code == 200
|
464
|
+
end
|
465
|
+
|
466
|
+
# Leaves a room (but does not forget about it).
|
467
|
+
#
|
468
|
+
# @param room [String] The room to leave.
|
469
|
+
# @return [Boolean] `true` if the room was left successfully,
|
470
|
+
# otherwise `false`.
|
471
|
+
def leave(room)
|
472
|
+
room = get_room_id room if room.start_with? '#'
|
473
|
+
make_request(:post, "/rooms/#{room}/leave").code == 200
|
474
|
+
end
|
475
|
+
|
476
|
+
# Unbans a user from a room.
|
477
|
+
#
|
478
|
+
# @param room [String] The room to unban the user from.
|
479
|
+
# @param user [String] The user to unban.
|
480
|
+
# @return [Boolean] `true` if the user was successfully unbanned,
|
481
|
+
# otherwise `false`.
|
482
|
+
def unban(room, user)
|
483
|
+
room = get_room_id room if room.start_with? '#'
|
484
|
+
make_request(
|
485
|
+
:post,
|
486
|
+
"/rooms/#{room}/unban",
|
487
|
+
content: { user_id: user }
|
488
|
+
).code == 200
|
489
|
+
end
|
490
|
+
|
491
|
+
# Performs a login attempt.
|
492
|
+
#
|
493
|
+
# @note A successful login will update the {#access_token access_token}
|
494
|
+
# to the new one returned from the login response.
|
495
|
+
#
|
496
|
+
# @param method [String] The method to use for logging in.
|
497
|
+
# For user/password combination, this should be `m.login.password`.
|
498
|
+
# @param options [Hash{String=>String}] Options to pass for logging in.
|
499
|
+
# For a password login, this should contain a key `:user` for the
|
500
|
+
# username, and a key `:password` for the password.
|
501
|
+
# @return [Hash] The response from the server. A successful login will
|
502
|
+
# return a hash containing the user id, access token, and homeserver.
|
503
|
+
#
|
504
|
+
# @example Logging in with username and password
|
505
|
+
# login('m.login.password', user: '@snoo:reddit.com', password: 'hunter2')
|
506
|
+
def login(method, options = {})
|
507
|
+
response = make_request(
|
508
|
+
:post,
|
509
|
+
'/login',
|
510
|
+
content: { type: method }.merge!(options)
|
511
|
+
)
|
512
|
+
|
513
|
+
# Update the local access token
|
514
|
+
@access_token = response['access_token']
|
515
|
+
|
516
|
+
response.parsed_response
|
517
|
+
end
|
518
|
+
|
519
|
+
# Logs out.
|
520
|
+
#
|
521
|
+
# @note This will **invalidate the access token**. It will no longer be
|
522
|
+
# valid for API calls.
|
523
|
+
#
|
524
|
+
# @return [Hash] The response from the server (an empty hash).
|
525
|
+
def logout
|
526
|
+
response = make_request :post, '/logout'
|
527
|
+
|
528
|
+
# A successful logout means the access token has been invalidated
|
529
|
+
@access_token = nil
|
530
|
+
|
531
|
+
response.parsed_response
|
532
|
+
end
|
533
|
+
|
534
|
+
# Gets a new access token to use for API calls when the current one
|
535
|
+
# expires.
|
536
|
+
#
|
537
|
+
# @note On success, the internal {#access_token access_token} will be
|
538
|
+
# updated automatically for use in subsequent API calls.
|
539
|
+
#
|
540
|
+
# @param token [String,nil] The `refresh_token` to provide for the server
|
541
|
+
# when requesting a new token. If not set, the internal refresh and
|
542
|
+
# access tokens will be used.
|
543
|
+
# @return [Hash] The response hash from the server will contain the new
|
544
|
+
# access token and a refresh token to use the next time a new access
|
545
|
+
# token is needed.
|
546
|
+
def refresh(token = nil)
|
547
|
+
refresh_token = token || @refresh_token || @access_token
|
548
|
+
|
549
|
+
response = make_request(
|
550
|
+
:post,
|
551
|
+
'/tokenrefresh',
|
552
|
+
content: { refresh_token: refresh_token }
|
553
|
+
)
|
554
|
+
|
555
|
+
@access_token = response['access_token']
|
556
|
+
@refresh_token = response['refresh_token']
|
557
|
+
|
558
|
+
response.parsed_response
|
559
|
+
end
|
560
|
+
|
561
|
+
# Gets the presence list for a user.
|
562
|
+
#
|
563
|
+
# @param user [String] The user whose list to get.
|
564
|
+
# @return [Array] A list of presences for this user.
|
565
|
+
#
|
566
|
+
# @todo The official documentation on this endpoint is weird, what does
|
567
|
+
# this really do?
|
568
|
+
def get_presence_list(user)
|
569
|
+
make_request(:get, "/presence/list/#{user}").parsed_response
|
570
|
+
end
|
571
|
+
|
572
|
+
# Adds or removes users from a user's presence list.
|
573
|
+
#
|
574
|
+
# @param user [String] The user whose list to modify.
|
575
|
+
# @param data [Hash{String=>Array<String>}] Contains two arrays,
|
576
|
+
# `invite` and `drop`. Users listed in the `invite` array will be
|
577
|
+
# invited to join the presence list. Users listed in the `drop` array
|
578
|
+
# will be removed from the presence list.
|
579
|
+
# Note that both arrays are not required but at least one must be
|
580
|
+
# present.
|
581
|
+
# @return [Boolean] `true` if the list was successfully updated,
|
582
|
+
# otherwise `false`.
|
583
|
+
#
|
584
|
+
# @example Add and remove two users
|
585
|
+
# update_presence_list(
|
586
|
+
# '@me:home.org',
|
587
|
+
# {
|
588
|
+
# invite: ['@friend:home.org'],
|
589
|
+
# drop: ['@enemy:other.org']
|
590
|
+
# }
|
591
|
+
# )
|
592
|
+
def update_presence_list(user, data)
|
593
|
+
make_request(
|
594
|
+
:post,
|
595
|
+
"/presence/list/#{user}",
|
596
|
+
content: { presence_diff: data }
|
597
|
+
).code == 200
|
598
|
+
end
|
599
|
+
|
600
|
+
# Gets the presence status of a user.
|
601
|
+
#
|
602
|
+
# @param user [String] The user to query.
|
603
|
+
# @return [Hash] Hash with information about the user's presence,
|
604
|
+
# contains information indicating if they are available and when
|
605
|
+
# they were last active.
|
606
|
+
def get_presence_status(user)
|
607
|
+
make_request(:get, "/presence/#{user}/status").parsed_response
|
608
|
+
end
|
609
|
+
|
610
|
+
# Updates the presence status of a user.
|
611
|
+
#
|
612
|
+
# @note Only the user for whom the {#access_token access_token} is
|
613
|
+
# valid for can have their presence updated.
|
614
|
+
#
|
615
|
+
# @param user [String] The user to update.
|
616
|
+
# @param status [String] The new status to set. Eg. `'online'`
|
617
|
+
# or `'offline'`.
|
618
|
+
# @param message [String,nil] If set, associates a message with the status.
|
619
|
+
# @return [Boolean] `true` if the presence was updated successfully,
|
620
|
+
# otherwise `false`.
|
621
|
+
def update_presence_status(user, status, message = nil)
|
622
|
+
content = { presenceState: { presence: status } }
|
623
|
+
|
624
|
+
content[:presenceState][:status_msg] = message if message
|
625
|
+
|
626
|
+
make_request(
|
627
|
+
:put,
|
628
|
+
"/presence/#{user}/status",
|
629
|
+
content: content
|
630
|
+
).code == 200
|
631
|
+
end
|
632
|
+
|
633
|
+
# Get the list of public rooms on the server.
|
634
|
+
#
|
635
|
+
# The `start` and `end` values returned in the result can be passed to
|
636
|
+
# `from` and `to`, for pagination purposes.
|
637
|
+
#
|
638
|
+
# @param from [String] The stream token to start looking from.
|
639
|
+
# @param to [String] The stream token to stop looking at.
|
640
|
+
# @param limit [Fixnum] Maximum number of results to return in one request.
|
641
|
+
# @param direction ['f', 'b'] Direction to look in.
|
642
|
+
# @return [Hash] Hash containing the list of rooms (in the `chunk` value),
|
643
|
+
# and pagination parameters `start` and `end`.
|
644
|
+
def rooms(from: 'START', to: 'END', limit: 10, direction: 'b')
|
645
|
+
make_request(
|
646
|
+
:get,
|
647
|
+
'/publicRooms',
|
648
|
+
params: {
|
649
|
+
from: start,
|
650
|
+
to: to,
|
651
|
+
limit: limit,
|
652
|
+
dir: direction
|
653
|
+
}
|
654
|
+
).parsed_response
|
655
|
+
end
|
656
|
+
|
657
|
+
private
|
658
|
+
|
659
|
+
# Create an options Hash to pass to a server request.
|
660
|
+
#
|
661
|
+
# This method embeds the {#access_token access_token} into the
|
662
|
+
# query parameters.
|
663
|
+
#
|
664
|
+
# @param params [Hash{String=>String},nil] Query parameters to add to
|
665
|
+
# the options hash.
|
666
|
+
# @param content [Hash,nil] Request content to add to the options hash.
|
667
|
+
# @return [Hash] Options hash ready to be passed into a server request.
|
668
|
+
def make_request_options(params, content)
|
669
|
+
options = {
|
670
|
+
query: @access_token ? { access_token: @access_token } : {}
|
671
|
+
}
|
672
|
+
|
673
|
+
options[:query].merge!(params) if params.is_a? Hash
|
674
|
+
options[:body] = content.to_json if content.is_a? Hash
|
675
|
+
|
676
|
+
options
|
677
|
+
end
|
678
|
+
|
679
|
+
# Helper method for performing requests to the homeserver.
|
680
|
+
#
|
681
|
+
# @param method [Symbol] HTTP request method to use. Use only symbols
|
682
|
+
# available as keys in {METHODS}.
|
683
|
+
# @param path [String] The API path to query, relative to the base
|
684
|
+
# API path, eg. `/login`.
|
685
|
+
# @param params [Hash{String=>String}] Additional parameters to include
|
686
|
+
# in the query string (part of the URL, not put in the request body).
|
687
|
+
# @param content [Hash] Content to put in the request body, must
|
688
|
+
# be serializable to json via `#to_json`.
|
689
|
+
# @yield [fragment] HTTParty will call the block during the request.
|
690
|
+
#
|
691
|
+
# @return [HTTParty::Response] The HTTParty response object.
|
692
|
+
def make_request(method, path, params: nil, content: nil, &block)
|
693
|
+
path = @base_uri + URI.encode(path)
|
694
|
+
options = make_request_options params, content
|
695
|
+
|
696
|
+
parse_response METHODS[method].call(path, options, &block)
|
697
|
+
end
|
698
|
+
|
699
|
+
# Parses a HTTParty Response object and returns it if it was successful.
|
700
|
+
#
|
701
|
+
# @param response [HTTParty::Response] The response object to parse.
|
702
|
+
# @return [HTTParty::Response] The same response object that was passed
|
703
|
+
# in, if the request was successful.
|
704
|
+
#
|
705
|
+
# @raise [ForbiddenError] If a `403` response code was returned from the
|
706
|
+
# request.
|
707
|
+
# @raise [NotFoundError] If a `404` response code was returned from the
|
708
|
+
# request.
|
709
|
+
# @raise [RequestError] If an error object was returned from the server.
|
710
|
+
# @raise [ApiError] If an unparsable error was returned from the server.
|
711
|
+
#
|
712
|
+
# rubocop:disable MethodLength
|
713
|
+
def parse_response(response)
|
714
|
+
case response.code
|
715
|
+
when 200 # OK
|
716
|
+
response
|
717
|
+
when 403 # Forbidden
|
718
|
+
raise ForbiddenError, 'You do not have access to that resource'
|
719
|
+
when 404 # Not found
|
720
|
+
raise NotFoundError, 'The specified resource could not be found'
|
721
|
+
else
|
722
|
+
if %w{(errcode), (error)}.all? { |k| response.include? k }
|
723
|
+
raise RequestError.new(response.parsed_response), 'Request failed'
|
724
|
+
end
|
725
|
+
|
726
|
+
raise ApiError, 'Unknown API error occurred when carrying out request'
|
727
|
+
end
|
728
|
+
end
|
729
|
+
end
|
730
|
+
end
|
metadata
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chatrix
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.pre
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Hellberg
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.13'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.12'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.12'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.10'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.10'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: yard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.8'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.8'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: redcarpet
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.3'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.3'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.40.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.40.0
|
125
|
+
description:
|
126
|
+
email:
|
127
|
+
- sharparam@sharparam.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".editorconfig"
|
133
|
+
- ".gitignore"
|
134
|
+
- ".rspec"
|
135
|
+
- ".travis.yml"
|
136
|
+
- ".yardopts"
|
137
|
+
- Gemfile
|
138
|
+
- LICENSE
|
139
|
+
- README.md
|
140
|
+
- Rakefile
|
141
|
+
- bin/console
|
142
|
+
- bin/setup
|
143
|
+
- chatrix.gemspec
|
144
|
+
- lib/chatrix.rb
|
145
|
+
- lib/chatrix/errors.rb
|
146
|
+
- lib/chatrix/matrix.rb
|
147
|
+
- lib/chatrix/version.rb
|
148
|
+
homepage: https://github.com/Sharparam/chatrix
|
149
|
+
licenses:
|
150
|
+
- MIT
|
151
|
+
metadata: {}
|
152
|
+
post_install_message:
|
153
|
+
rdoc_options: []
|
154
|
+
require_paths:
|
155
|
+
- lib
|
156
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - ">"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 1.3.1
|
166
|
+
requirements: []
|
167
|
+
rubyforge_project:
|
168
|
+
rubygems_version: 2.5.1
|
169
|
+
signing_key:
|
170
|
+
specification_version: 4
|
171
|
+
summary: Ruby implementation of the Matrix API
|
172
|
+
test_files: []
|
173
|
+
has_rdoc:
|