-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add first send api methods and PromiseKit extension
- Loading branch information
Koray Koska
committed
Jan 29, 2019
1 parent
5326db7
commit 21bfd58
Showing
9 changed files
with
460 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
Sources/TelegramBot/Json/SendApi/TelegramSendForwardMessage.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// | ||
// TelegramSendForwardMessage.swift | ||
// TelegramBot | ||
// | ||
// Created by Koray Koska on 29.01.19. | ||
// | ||
|
||
import Foundation | ||
|
||
public final class TelegramSendForwardMessage: Codable { | ||
|
||
// MARK: - Primitive types | ||
|
||
/// Unique identifier for the target chat or | ||
/// username of the target channel (in the | ||
/// format @channelusername) | ||
public var chatId: TelegramSendChatIdentifier | ||
|
||
/// Unique identifier for the chat where the original message was sent (or | ||
/// channel username in the format @channelusername) | ||
public var fromChatId: TelegramSendChatIdentifier | ||
|
||
/// Sends the message silently. Users will receive a notification with no | ||
/// sound. | ||
public var disableNotification: Bool? | ||
|
||
/// Message identifier in the chat specified in fromChatId | ||
public var messageId: Int | ||
|
||
// MARK: - Initialization | ||
|
||
public init(chatId: TelegramSendChatIdentifier, fromChatId: TelegramSendChatIdentifier, disableNotification: Bool? = nil, messageId: Int) { | ||
self.chatId = chatId | ||
self.fromChatId = fromChatId | ||
self.disableNotification = disableNotification | ||
self.messageId = messageId | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// | ||
// TelegramSendPhoto.swift | ||
// TelegramBot | ||
// | ||
// Created by Koray Koska on 29.01.19. | ||
// | ||
|
||
import Foundation | ||
|
||
public final class TelegramSendPhoto: Codable { | ||
|
||
// MARK: - Primitive types | ||
|
||
/// Unique identifier for the target chat or | ||
/// username of the target channel (in the | ||
/// format @channelusername) | ||
public var chatId: TelegramSendChatIdentifier | ||
|
||
/// Photo to send. Pass a file_id as String to send a photo | ||
/// that exists on the Telegram servers (recommended), | ||
/// pass an HTTP URL as a String for Telegram to get a | ||
/// photo from the Internet | ||
public var photo: String | ||
|
||
/// Photo caption (may also be used when resending | ||
/// photos by file_id), 0-1024 characters | ||
public var caption: String? | ||
|
||
/// Send Markdown or HTML, if you want Telegram apps | ||
/// to show bold, italic, fixed-width text or inline URLs in | ||
/// the media caption. | ||
public var parseMode: TelegramSendMessage.ParseMode? | ||
|
||
/// Sends the message silently. Users will receive a | ||
/// notification with no sound. | ||
public var disableNotification: Bool? | ||
|
||
/// If the message is a reply, ID of the original message | ||
public var replyToMessageId: Int? | ||
|
||
/// Additional interface options. A JSON-serialized object | ||
/// for an inline keyboard, custom reply keyboard, | ||
/// instructions to remove reply keyboard or to force a | ||
/// reply from the user. | ||
public var replyMarkup: TelegramSendMessage.ReplyMarkup? | ||
|
||
// MARK: - Initialization | ||
|
||
public init( | ||
chatId: TelegramSendChatIdentifier, | ||
photo: String, | ||
caption: String? = nil, | ||
parseMode: TelegramSendMessage.ParseMode? = nil, | ||
disableNotification: Bool? = nil, | ||
replyToMessageId: Int? = nil, | ||
replyMarkup: TelegramSendMessage.ReplyMarkup? = nil | ||
) { | ||
self.chatId = chatId | ||
self.photo = photo | ||
self.caption = caption | ||
self.parseMode = parseMode | ||
self.disableNotification = disableNotification | ||
self.replyToMessageId = replyToMessageId | ||
self.replyMarkup = replyMarkup | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// | ||
// TelegramApiHttpProvider.swift | ||
// TelegramBot | ||
// | ||
// Created by Koray Koska on 29.01.19. | ||
// | ||
|
||
import Foundation | ||
import Dispatch | ||
|
||
public struct TelegramApiHttpProvider: TelegramApiProvider { | ||
|
||
let encoder: JSONEncoder | ||
let decoder: JSONDecoder | ||
|
||
let queue: DispatchQueue | ||
|
||
let session: URLSession | ||
|
||
static let headers = [ | ||
"Accept": "application/json", | ||
"Content-Type": "application/json" | ||
] | ||
|
||
public let url: String | ||
|
||
public init(url: String, session: URLSession = URLSession(configuration: .default)) { | ||
let encoder = JSONEncoder() | ||
encoder.keyEncodingStrategy = .convertToSnakeCase | ||
self.encoder = encoder | ||
let decoder = JSONDecoder() | ||
decoder.keyDecodingStrategy = .convertFromSnakeCase | ||
self.decoder = decoder | ||
|
||
self.url = url | ||
self.session = session | ||
|
||
// Concurrent queue for faster concurrent requests | ||
self.queue = DispatchQueue(label: "TelegramApiHttpProvider", attributes: .concurrent) | ||
} | ||
|
||
public func send<Params: Codable, Result>(method: String, request: Params, response: @escaping TelegramApiResponseCompletion<Result>) { | ||
queue.async { | ||
|
||
let body: Data | ||
do { | ||
body = try self.encoder.encode(request) | ||
} catch { | ||
let err = TelegramResponse<Result>(error: .requestFailed(error)) | ||
response(err) | ||
return | ||
} | ||
|
||
guard let url = URL(string: "\(self.url)/\(method)") else { | ||
let err = TelegramResponse<Result>(error: .requestFailed(nil)) | ||
response(err) | ||
return | ||
} | ||
|
||
var req = URLRequest(url: url) | ||
req.httpMethod = "POST" | ||
req.httpBody = body | ||
for (k, v) in type(of: self).headers { | ||
req.addValue(v, forHTTPHeaderField: k) | ||
} | ||
|
||
let task = self.session.dataTask(with: req) { data, urlResponse, error in | ||
guard let urlResponse = urlResponse as? HTTPURLResponse, let data = data, error == nil else { | ||
let err = TelegramResponse<Result>(error: .serverError(error)) | ||
response(err) | ||
return | ||
} | ||
|
||
let status = urlResponse.statusCode | ||
guard status >= 200 && status < 300 else { | ||
// This is a non typical error response and should be considered a server error. | ||
let err = TelegramResponse<Result>(error: .serverError(nil)) | ||
response(err) | ||
return | ||
} | ||
|
||
do { | ||
let decoded = try self.decoder.decode(TelegramApiResponse<Result>.self, from: data) | ||
// We got the Result object | ||
let res = TelegramResponse(response: decoded) | ||
response(res) | ||
} catch { | ||
// We don't have the response we expected... | ||
let err = TelegramResponse<Result>(error: .decodingError(error)) | ||
response(err) | ||
} | ||
} | ||
task.resume() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// | ||
// TelegramApiProvider.swift | ||
// TelegramBot | ||
// | ||
// Created by Koray Koska on 29.01.19. | ||
// | ||
|
||
import Foundation | ||
|
||
public protocol TelegramApiProvider { | ||
|
||
typealias TelegramApiResponseCompletion<Result: Codable> = (_ resp: TelegramResponse<Result>) -> Void | ||
|
||
func send<Params: Codable, Result: Codable>(method: String, request: Params, response: @escaping TelegramApiResponseCompletion<Result>) | ||
} | ||
|
||
public struct TelegramResponse<Result: Codable> { | ||
|
||
public enum Error: Swift.Error { | ||
case emptyResponse | ||
case requestFailed(Swift.Error?) | ||
case connectionFailed(Swift.Error?) | ||
case serverError(Swift.Error?) | ||
case decodingError(Swift.Error?) | ||
} | ||
|
||
public enum Status<Result> { | ||
case success(Result) | ||
case failure(Swift.Error) | ||
} | ||
|
||
public let status: Status<Result> | ||
|
||
public var result: Result? { | ||
return status.result | ||
} | ||
|
||
public var error: Swift.Error? { | ||
return status.error | ||
} | ||
|
||
// MARK: - Initialization | ||
|
||
public init(status: Status<Result>) { | ||
self.status = status | ||
} | ||
|
||
/// Initialize with any Error object | ||
public init(error: Swift.Error) { | ||
self.status = .failure(error) | ||
} | ||
|
||
/// Initialize with a response | ||
public init(response: TelegramApiResponse<Result>) { | ||
if let result = response.result { | ||
self.status = .success(result) | ||
} else if let error = response.error { | ||
self.status = .failure(error) | ||
} else { | ||
self.status = .failure(Error.emptyResponse) | ||
} | ||
} | ||
|
||
/// For convenience, initialize with one of the common errors | ||
public init(error: Error) { | ||
self.status = .failure(error) | ||
} | ||
} | ||
|
||
/// Convenience properties | ||
extension TelegramResponse.Status { | ||
public var isSuccess: Bool { | ||
switch self { | ||
case .success: | ||
return true | ||
case .failure: | ||
return false | ||
} | ||
} | ||
|
||
public var isFailure: Bool { | ||
return !isSuccess | ||
} | ||
|
||
public var result: Result? { | ||
switch self { | ||
case .success(let value): | ||
return value | ||
case .failure: | ||
return nil | ||
} | ||
} | ||
|
||
public var error: Error? { | ||
switch self { | ||
case .failure(let error): | ||
return error | ||
case .success: | ||
return nil | ||
} | ||
} | ||
} | ||
|
||
extension TelegramResponse.Status: CustomStringConvertible { | ||
public var description: String { | ||
switch self { | ||
case .success: | ||
return "SUCCESS" | ||
case .failure: | ||
return "FAILURE" | ||
} | ||
} | ||
} | ||
|
||
extension TelegramResponse.Status: CustomDebugStringConvertible { | ||
public var debugDescription: String { | ||
switch self { | ||
case .success(let value): | ||
return "SUCCESS: \(value)" | ||
case .failure(let error): | ||
return "FAILURE: \(error)" | ||
} | ||
} | ||
} |
Oops, something went wrong.