Skip to content

Commit

Permalink
add session
Browse files Browse the repository at this point in the history
  • Loading branch information
marty-suzuki committed Oct 7, 2017
1 parent dfaa6bb commit 7ef4944
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 17 deletions.
33 changes: 16 additions & 17 deletions Example/Pods/Pods.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions URLEmbeddedView.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
objects = {

/* Begin PBXBuildFile section */
370325561F8944CF0057A85B /* OGSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370325551F8944CF0057A85B /* OGSession.swift */; };
370325581F8944E60057A85B /* OpenGraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370325571F8944E60057A85B /* OpenGraph.swift */; };
3703255A1F8944FB0057A85B /* OGRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370325591F8944FB0057A85B /* OGRequest.swift */; };
3703255C1F8945160057A85B /* HtmlRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3703255B1F8945160057A85B /* HtmlRequest.swift */; };
3703255E1F8945370057A85B /* YoutubeEmbedRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3703255D1F8945370057A85B /* YoutubeEmbedRequest.swift */; };
374BF8F21F45E3F900EE3354 /* AutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374BF8F11F45E3F900EE3354 /* AutoLayout.swift */; };
ED602B6E1F42D4EB00A45816 /* URLEmbeddedView.h in Headers */ = {isa = PBXBuildFile; fileRef = ED602B6C1F42D4EB00A45816 /* URLEmbeddedView.h */; settings = {ATTRIBUTES = (Public, ); }; };
ED602B841F42D51100A45816 /* AttributedTextProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED602B741F42D51100A45816 /* AttributedTextProvider.swift */; };
Expand All @@ -29,6 +34,11 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
370325551F8944CF0057A85B /* OGSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OGSession.swift; sourceTree = "<group>"; };
370325571F8944E60057A85B /* OpenGraph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenGraph.swift; sourceTree = "<group>"; };
370325591F8944FB0057A85B /* OGRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OGRequest.swift; sourceTree = "<group>"; };
3703255B1F8945160057A85B /* HtmlRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HtmlRequest.swift; sourceTree = "<group>"; };
3703255D1F8945370057A85B /* YoutubeEmbedRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YoutubeEmbedRequest.swift; sourceTree = "<group>"; };
374BF8F11F45E3F900EE3354 /* AutoLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoLayout.swift; sourceTree = "<group>"; };
ED602B691F42D4EB00A45816 /* URLEmbeddedView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = URLEmbeddedView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
ED602B6C1F42D4EB00A45816 /* URLEmbeddedView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = URLEmbeddedView.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -65,6 +75,18 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
370325541F8944CF0057A85B /* Core */ = {
isa = PBXGroup;
children = (
370325571F8944E60057A85B /* OpenGraph.swift */,
370325551F8944CF0057A85B /* OGSession.swift */,
370325591F8944FB0057A85B /* OGRequest.swift */,
3703255B1F8945160057A85B /* HtmlRequest.swift */,
3703255D1F8945370057A85B /* YoutubeEmbedRequest.swift */,
);
path = Core;
sourceTree = "<group>";
};
ED602B5F1F42D4EB00A45816 = {
isa = PBXGroup;
children = (
Expand All @@ -85,6 +107,7 @@
ED602B6B1F42D4EB00A45816 /* URLEmbeddedView */ = {
isa = PBXGroup;
children = (
370325541F8944CF0057A85B /* Core */,
374BF8F11F45E3F900EE3354 /* AutoLayout.swift */,
ED602B741F42D51100A45816 /* AttributedTextProvider.swift */,
ED602B751F42D51100A45816 /* AttributeManager.swift */,
Expand Down Expand Up @@ -198,9 +221,11 @@
buildActionMask = 2147483647;
files = (
ED602B8F1F42D51100A45816 /* OGImageProvider.swift in Sources */,
3703255A1F8944FB0057A85B /* OGRequest.swift in Sources */,
ED602B8A1F42D51100A45816 /* OGData.swift in Sources */,
ED602B891F42D51100A45816 /* NSUserDefaults+URLEmbeddedView.swift in Sources */,
ED602B851F42D51100A45816 /* AttributeManager.swift in Sources */,
370325561F8944CF0057A85B /* OGSession.swift in Sources */,
ED602B911F42D51100A45816 /* URLEmbeddedView.swift in Sources */,
ED602B8C1F42D51100A45816 /* OGDataCacheManager.swift in Sources */,
ED602B901F42D51100A45816 /* TaskContainable.swift in Sources */,
Expand All @@ -209,9 +234,12 @@
ED602B841F42D51100A45816 /* AttributedTextProvider.swift in Sources */,
ED602B881F42D51100A45816 /* NSTimeInterval+Util.swift in Sources */,
ED602B8B1F42D51100A45816 /* OGData+CoreDataProperties.swift in Sources */,
3703255C1F8945160057A85B /* HtmlRequest.swift in Sources */,
370325581F8944E60057A85B /* OpenGraph.swift in Sources */,
ED602B871F42D51100A45816 /* MD5.swift in Sources */,
ED602B8D1F42D51100A45816 /* OGDataProvider.swift in Sources */,
374BF8F21F45E3F900EE3354 /* AutoLayout.swift in Sources */,
3703255E1F8945370057A85B /* YoutubeEmbedRequest.swift in Sources */,
ED602B931F42D51100A45816 /* URLImageView.swift in Sources */,
ED602B861F42D51100A45816 /* LinkIconView.swift in Sources */,
);
Expand Down
28 changes: 28 additions & 0 deletions URLEmbeddedView/Core/HtmlRequest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// HtmlRequest.swift
// URLEmbeddedView
//
// Created by marty-suzuki on 2017/10/08.
// Copyright © 2017年 marty-suzuki. All rights reserved.
//

import Foundation
import Kanna

struct HtmlRequest: OGRequest {
let url: URL

init(url: URL) {
self.url = url
}

static func response(data: Data) throws -> OpenGraph.HTML {
guard
let html = Kanna.HTML(html: data, encoding: String.Encoding.utf8),
let header = html.head
else {
throw OGSession.Error.castFaild
}
return try OpenGraph.HTML(element: header) ?? { throw OGSession.Error.htmlDecodeFaild }()
}
}
27 changes: 27 additions & 0 deletions URLEmbeddedView/Core/OGRequest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// OGRequest.swift
// URLEmbeddedView
//
// Created by marty-suzuki on 2017/10/08.
// Copyright © 2017年 marty-suzuki. All rights reserved.
//

import Foundation

private let userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Safari/601.1.42"

protocol OGRequest {
associatedtype Response
var url: URL { get }
var urlRequest: URLRequest { get }
static func response(data: Data) throws -> Response
}

extension OGRequest {
var urlRequest: URLRequest {
var request = URLRequest(url: url)
request.setValue(userAgent, forHTTPHeaderField: "User-Agent")
request.timeoutInterval = 5
return request
}
}
49 changes: 49 additions & 0 deletions URLEmbeddedView/Core/OGSession.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// File.swift
// URLEmbeddedView
//
// Created by marty-suzuki on 2017/10/08.
//

import Foundation

final class OGSession {
struct Task {
let uuidString: String
let task: URLSessionDataTask
}

enum Error: Swift.Error {
case castFaild
case jsonDecodeFaild
case htmlDecodeFaild
case other(Swift.Error)
}

private let session: URLSession

init(configuration: URLSessionConfiguration = .default) {
configuration.timeoutIntervalForRequest = 30
configuration.timeoutIntervalForResource = 60
self.session = URLSession(configuration: configuration)
}

func send<T: OGRequest>(_ request: T, completion: @escaping (T.Response?, Error?) -> Void) -> Task {
let task = session.dataTask(with: request.urlRequest) { data, response, error in
guard let data = data else {
let e = error.map { Error.other($0) }
completion(nil, e)
return
}
do {
let response = try T.response(data: data)
completion(response, nil)
} catch let e as Error {
completion(nil, e)
} catch let e {
completion(nil, .other(e))
}
}
return Task(uuidString: UUID().uuidString, task: task)
}
}
67 changes: 67 additions & 0 deletions URLEmbeddedView/Core/OpenGraph.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// OpenGraph.swift
// URLEmbeddedView
//
// Created by marty-suzuki on 2017/10/08.
// Copyright © 2017年 marty-suzuki. All rights reserved.
//

import Foundation
import Kanna

/// name space
enum OpenGraph {}

extension OpenGraph {
struct HTML {
private enum Const {
static let metaTagKey = "meta"
static let propertyKey = "property"
static let contentKey = "content"
static let propertyPrefix = "og:"
}

struct Metadata {
let property: String
let content: String
}
let metaList: [Metadata]

init?(element: XMLElement) {
let metaTags = element.xpath(Const.metaTagKey)
let metaList = metaTags.enumerated().flatMap { _, metaTag -> Metadata? in
guard
let property = metaTag[Const.propertyKey],
let content = metaTag[Const.contentKey],
property.hasPrefix(Const.propertyPrefix)
else { return nil }
return Metadata(property: property, content: content)
}
if metaList.isEmpty { return nil }
self.metaList = metaList
}
}
}

extension OpenGraph {
struct Youtube {
let title: String
let type: String
let providerName: String
let thumbnailUrl: String

init?(json: [AnyHashable : Any]) {
guard let title = json["title"] as? String else { return nil }
self.title = title

guard let type = json["type"] as? String else { return nil }
self.type = type

guard let providerName = json["provider_name"] as? String else { return nil }
self.providerName = providerName

guard let thumbnailUrl = json["thumbnail_url"] as? String else { return nil }
self.thumbnailUrl = thumbnailUrl
}
}
}
27 changes: 27 additions & 0 deletions URLEmbeddedView/Core/YoutubeEmbedRequest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// YoutubeEmbedRequest.swift
// URLEmbeddedView
//
// Created by marty-suzuki on 2017/10/08.
// Copyright © 2017年 marty-suzuki. All rights reserved.
//

import Foundation

struct YoutubeEmbedRequest: OGRequest {
let url: URL

init?(url: URL) {
guard
let escapedString = url.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: "https://www.youtube.com/oembed?url=\(escapedString)")
else { return nil }
self.url = url
}

static func response(data: Data) throws -> OpenGraph.Youtube {
let rawJson = try JSONSerialization.jsonObject(with: data, options: [])
let json = try (rawJson as? [AnyHashable : Any]) ?? { throw OGSession.Error.castFaild }()
return try OpenGraph.Youtube(json: json) ?? { throw OGSession.Error.jsonDecodeFaild }()
}
}

0 comments on commit 7ef4944

Please sign in to comment.