diff --git a/README.md b/README.md index b62114b..f539e91 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,68 @@ # DHTSpider >A Very Simple Spider With DHT Crawler, Written by C#. -* The bittorrent library bases on DhtWalker,MonoTorrent. +* The bittorrent library bases on MonoTorrent. - - - -## 介绍 +### 介绍 DHTSpider 是一个由C#编写的 DHT 爬虫, 从全球` DHT ` 网络里"`嗅探`"正在下载的资源, 并把资源`metadata`(种子信息)进行抓取下载. -## 相关 +### 相关 -使用 `MongoDB` 进行数据存储. +>Cache -使用 `ElasticSearch` 进行全文检索(待定). ++ 使用 `Memory` > UseDefaultCache ( 默认 ) ++ 使用 `Redis` > UseRedisCache ( TODO ) +>Queue -## 环境 ++ 使用 `Memory` > UseDefaultQueue ( 默认 ) ++ 使用 `Redis` > UseRedisQueue ( TODO ) + +>Store + ++ 使用 `MongoDB` > UseMongoDBStore ( TODO ) ++ 使用 `ElasticSearch` > UseElasticSearchStore ( TODO ) + +>Log > `NLog` + +>Ioc > `Autofac` + +### 环境 1. `.net` 版本 `>=4.5.2` -2. 运行的机器需要`独立IP` , 能够访问外网 ( `翻墙` ) +2. 运行的机器需要`独立IP` , 内网机器需要做下`端口映射` -## 参数 +### 使用 + +```c# + + var spider = SpiderConfiguration.Create() //使用默认配置 + .UseDefaultCache() //默认使用内存缓存 + .UseDefaultQueue() //默认使用内存队列 + .Start(); -``` -Setting.InitSetting();//初始化相关参数 ``` -``` +### 配置 + +```c# - LocalPort = 6881; - - IsSaveTorrent = true; - - TorrentSavePath = @"torrent\"; - - IsUsingMongoDb = false; - - InitResolverThreadCount = 10; - - MaxResolverThreadCount = 50; - - WaitSeedsCount = 100; - - - //DhtSpiderSetting - - DhtSpiderSetting.MaxSendQueue = 50; - DhtSpiderSetting.MaxFindSendPer = 100; - DhtSpiderSetting.MaxWaitCount = 1000; - DhtSpiderSetting.MaxCacheCount = 5000; + var spider = SpiderConfiguration.Create(new SpiderSetting() + { + LocalPort = 6881, //使用端口 + IsSaveTorrent = true, //是否保存torrent + TorrentSavePath = "", //torrent保存路径 + MaxSpiderThreadCount = 1, //爬虫线程数 + MaxDownLoadThreadCount = 20 //下载线程数 + }) + .UseRedisCache() //使用redis缓存 + .UseRedisQueue() //使用redis队列 + .UseMongoDBStore() //使用mongodb存储 + .Start(); ``` -## 感谢 -项目开发中,`bittorrent`相关类库参考了 `DhtWalker` 和 `MonoTorrent`, 在此感谢作者 →_→ diff --git a/SimpleClient/Program.cs b/SimpleClient/Program.cs index 31a896a..1800d7f 100644 --- a/SimpleClient/Program.cs +++ b/SimpleClient/Program.cs @@ -13,18 +13,16 @@ namespace SimpleClient { var spider = SpiderConfiguration.Create(new SpiderSetting() { - LocalPort = 6881, - IsSaveTorrent = true, - TorrentSavePath = "", - MaxSpiderThreadCount = 1, - MaxDownLoadThreadCount = 20 + LocalPort = 6881,//使用端口 + IsSaveTorrent = true,//是否保存torrent + TorrentSavePath = "",//torrent保存路径 + MaxSpiderThreadCount = 1,//爬虫线程数 + MaxDownLoadThreadCount = 20//下载线程数 }) - .UseDefaultCache() - .UseDefaultQueue() - //.UseRedisQueue() - //.UseElasticSearchStore() - .UseMongoDBStore() - .Start(); + .UseDefaultCache() //默认使用内存缓存 + .UseDefaultQueue() //默认使用内存队列 + .Start(); + Console.ReadKey(); } diff --git a/Spider/Cache/RedisCache.cs b/Spider/Cache/RedisCache.cs index e60aa66..cfafd55 100644 --- a/Spider/Cache/RedisCache.cs +++ b/Spider/Cache/RedisCache.cs @@ -9,6 +9,7 @@ namespace Spider.Cache { public class RedisCache : ICache { + //TODO public RedisCache() { } diff --git a/Spider/Core/DHTSpider.cs b/Spider/Core/DHTSpider.cs index 8aac19a..69397bd 100644 --- a/Spider/Core/DHTSpider.cs +++ b/Spider/Core/DHTSpider.cs @@ -1,35 +1,20 @@ -using Spider.Core.IoSocket; -using Spider.Core.UdpServer; -using Spider.Log; +using Spider.Log; using Spider.Queue; using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.IO; -using System.Linq; using System.Net; -using System.Text; using System.Threading; using System.Threading.Tasks; using Tancoder.Torrent; using Tancoder.Torrent.BEncoding; -using Tancoder.Torrent.Client; -using Tancoder.Torrent.Client.Messages; using Tancoder.Torrent.Dht; -using Tancoder.Torrent.Dht.Listeners; using Tancoder.Torrent.Dht.Messages; namespace Spider.Core { public class DHTSpider : IDhtEngine { - private static List BOOTSTRAP_NODES = new List() { - new IPEndPoint(Dns.GetHostEntry("router.bittorrent.com").AddressList[0], 6881), - new IPEndPoint(Dns.GetHostEntry("dht.transmissionbt.com").AddressList[0], 6881) - }; - - private static int MaxNodesSize = 1000; - public DHTSpider(IPEndPoint localAddress, IQueue queue) { LocalAddress = localAddress; @@ -40,6 +25,14 @@ namespace Spider.Core Queue = queue; MessageQueue = new ConcurrentQueue>(); } + + private static List BOOTSTRAP_NODES = new List() { + new IPEndPoint(Dns.GetHostEntry("router.bittorrent.com").AddressList[0], 6881), + new IPEndPoint(Dns.GetHostEntry("dht.transmissionbt.com").AddressList[0], 6881) + }; + + private static int MaxNodesSize = 1000; + public ConcurrentQueue> MessageQueue; private object locker = new object(); public IMetaDataFilter Filter { get; set; } @@ -216,6 +209,7 @@ namespace Spider.Core } public void Stop() { + udpSocketListener.Stop(); } private void JoinDHTNetwork() diff --git a/Spider/Core/IoSocket/IoContextPool.cs b/Spider/Core/IoSocket/IoContextPool.cs deleted file mode 100644 index 205d49e..0000000 --- a/Spider/Core/IoSocket/IoContextPool.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Sockets; -using System.Text; -using System.Threading.Tasks; - -namespace Spider.Core.IoSocket -{ - /// - /// 与每个客户Socket相关联,进行Send和Receive投递时所需要的参数 - /// - internal sealed class IoContextPool - { - List pool; //为每一个Socket客户端分配一个SocketAsyncEventArgs,用一个List管理,在程序启动时建立。 - Int32 capacity; //pool对象池的容量 - Int32 boundary; //已分配和未分配对象的边界,大的是已经分配的,小的是未分配的 - - internal IoContextPool(Int32 capacity) - { - this.pool = new List(capacity); - this.boundary = 0; - this.capacity = capacity; - } - - /// - /// 往pool对象池中增加新建立的对象,因为这个程序在启动时会建立好所有对象, - /// 故这个方法只在初始化时会被调用,因此,没有加锁。 - /// - /// - /// - internal bool Add(SocketAsyncEventArgs arg) - { - if (arg != null && pool.Count < capacity) - { - pool.Add(arg); - boundary++; - return true; - } - else - return false; - } - internal Int32 Count - { - get { return this.pool.Count; } - } - /// - /// 取出集合中指定对象,内部使用 - /// - /// - /// - //internal SocketAsyncEventArgs Get(int index) - //{ - // if (index >= 0 && index < capacity) - // return pool[index]; - // else - // return null; - //} - - /// - /// 从对象池中取出一个对象,交给一个socket来进行投递请求操作 - /// - /// - internal SocketAsyncEventArgs Pop() - { - lock (this.pool) - { - if (boundary > 0) - { - --boundary; - return pool[boundary]; - } - else - return null; - } - } - - /// - /// 一个socket客户断开,与其相关的IoContext被释放,重新投入Pool中,备用。 - /// - /// - /// - internal bool Push(SocketAsyncEventArgs arg) - { - if (arg != null) - { - lock (this.pool) - { - int index = this.pool.IndexOf(arg, boundary); //找出被断开的客户,此处一定能查到,因此index不可能为-1,必定要大于0。 - if (index == boundary) //正好是边界元素 - boundary++; - else - { - this.pool[index] = this.pool[boundary]; //将断开客户移到边界上,边界右移 - this.pool[boundary++] = arg; - } - } - return true; - } - else - return false; - } - } -} diff --git a/Spider/Core/IoSocket/IoServer.cs b/Spider/Core/IoSocket/IoServer.cs deleted file mode 100644 index 0dac74e..0000000 --- a/Spider/Core/IoSocket/IoServer.cs +++ /dev/null @@ -1,263 +0,0 @@ -using Spider.Log; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Spider.Core.IoSocket -{ - - public delegate void MessageReceived(byte[] buffer, IPEndPoint endpoint); - /// - /// 基于SocketAsyncEventArgs 实现 IOCP 服务器 - /// - internal sealed class IoServer - { - /// - /// 监听Socket,用于接受客户端的连接请求 - /// - private Socket listenSocket; - - /// - /// 用于服务器执行的互斥同步对象 - /// - private static Mutex mutex = new Mutex(); - - /// - /// 用于每个I/O Socket操作的缓冲区大小 - /// - private Int32 bufferSize; - - /// - /// 服务器上连接的客户端总数 - /// - private Int32 numConnectedSockets; - - /// - /// 服务器能接受的最大连接数量 - /// - private Int32 numConnections; - - /// - /// 完成端口上进行投递所用的IoContext对象池 - /// - private IoContextPool ioContextPool; - - private IPEndPoint endpoint; - - /// - /// 构造函数,建立一个未初始化的服务器实例 - /// - /// 服务器的最大连接数据 - /// - internal IoServer(IPEndPoint endpoint) - { - this.endpoint = endpoint; - this.numConnectedSockets = 0; - this.numConnections = 10000; - this.bufferSize = 1024; - - this.ioContextPool = new IoContextPool(numConnections); - - // 为IoContextPool预分配SocketAsyncEventArgs对象 - for (Int32 i = 0; i < this.numConnections; i++) - { - SocketAsyncEventArgs ioContext = new SocketAsyncEventArgs(); - ioContext.Completed += new EventHandler(OnIOCompleted); - ioContext.SetBuffer(new Byte[this.bufferSize], 0, this.bufferSize); - - // 将预分配的对象加入SocketAsyncEventArgs对象池中 - this.ioContextPool.Add(ioContext); - } - } - - /// - /// 当Socket上的发送或接收请求被完成时,调用此函数 - /// - /// 激发事件的对象 - /// 与发送或接收完成操作相关联的SocketAsyncEventArg对象 - private void OnIOCompleted(object sender, SocketAsyncEventArgs e) - { - switch (e.LastOperation) - { - case SocketAsyncOperation.ReceiveFrom: - case SocketAsyncOperation.Receive: - this.ProcessReceive(e); - break; - } - ioContextPool.Add(e); - } - - public event MessageReceived MessageReceived; - - /// - ///接收完成时处理函数 - /// - /// 与接收完成操作相关联的SocketAsyncEventArg对象 - private void ProcessReceive(SocketAsyncEventArgs e) - { - // 检查远程主机是否关闭连接 - if (e.BytesTransferred > 0) - { - if (e.SocketError == SocketError.Success) - { - Socket s = (Socket)e.UserToken; - //判断所有需接收的数据是否已经完成 - if (s.Available == 0) - { - - //获取接收到的数据 - byte[] ByteArray = new byte[e.BytesTransferred]; - Array.Copy(e.Buffer, 0, ByteArray, 0, ByteArray.Length); - - MessageReceived?.Invoke(ByteArray, (IPEndPoint)e.RemoteEndPoint); - - } - else if (!s.ReceiveAsync(e)) //为接收下一段数据,投递接收请求,这个函数有可能同步完成,这时返回false,并且不会引发SocketAsyncEventArgs.Completed事件 - { - // 同步接收时处理接收完成事件 - this.ProcessReceive(e); - } - } - else - { - this.ProcessError(e); - } - } - else - { - this.CloseClientSocket(e); - } - } - - - - /// - /// 处理socket错误 - /// - /// - private void ProcessError(SocketAsyncEventArgs e) - { - Socket s = e.UserToken as Socket; - IPEndPoint localEp = s.LocalEndPoint as IPEndPoint; - - this.CloseClientSocket(s, e); - - string outStr = String.Format("套接字错误 {0}, IP {1}, 操作 {2}。", (Int32)e.SocketError, localEp, e.LastOperation); - - Logger.Fatal(outStr); - } - - /// - /// 关闭socket连接 - /// - /// SocketAsyncEventArg associated with the completed send/receive operation. - private void CloseClientSocket(SocketAsyncEventArgs e) - { - Socket s = e.UserToken as Socket; - this.CloseClientSocket(s, e); - } - - private void CloseClientSocket(Socket s, SocketAsyncEventArgs e) - { - Interlocked.Decrement(ref this.numConnectedSockets); - - // SocketAsyncEventArg 对象被释放,压入可重用队列。 - this.ioContextPool.Push(e); - string outStr = String.Format("客户 {0} 断开, 共有 {1} 个连接。", s.RemoteEndPoint.ToString(), this.numConnectedSockets); - Logger.Fatal(outStr); - try - { - s.Shutdown(SocketShutdown.Send); - } - catch (Exception) - { - // Throw if client has closed, so it is not necessary to catch. - } - finally - { - s.Close(); - } - } - - /// - /// 启动服务,开始监听 - /// - /// Port where the server will listen for connection requests. - internal void Start() - { - // 创建监听socket - this.listenSocket = new Socket(endpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); - //this.listenSocket.ReceiveBufferSize = this.bufferSize; - //this.listenSocket.SendBufferSize = this.bufferSize; - - listenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); - listenSocket.DontFragment = true; - listenSocket.EnableBroadcast = true; - listenSocket.Bind(endpoint); - - // Blocks the current thread to receive incoming messages. - //mutex.WaitOne(); - - Receive(); - } - - private void Receive() - { - var ReceiveThread = new Thread(new ThreadStart(() => - { - while (true) - { - if (ioContextPool.Count > 0) - { - SocketAsyncEventArgs ioContext = this.ioContextPool.Pop(); - if (!listenSocket.ReceiveFromAsync(ioContext)) - { - ProcessReceive(ioContext); - } - } - } - })); - - ReceiveThread.Start(); - } - - - /// - /// 停止服务 - /// - internal void Stop() - { - this.listenSocket.Close(); - //mutex.ReleaseMutex(); - } - - - internal void Send(IPEndPoint ipendpoint, byte[] data) - { - listenSocket.BeginSendTo(data, 0, data.Length, SocketFlags.None, ipendpoint, SendCallBack, listenSocket); - } - - private void SendCallBack(IAsyncResult result) - { - try - { - Socket sock = result.AsyncState as Socket; - - if (sock != null) - { - sock.EndSend(result); - Logger.Warn("SendCallBack"); - } - } - catch - { - - } - } - } -} diff --git a/Spider/Core/UdpServer/AsyncUDPServer.cs b/Spider/Core/UdpServer/AsyncUDPServer.cs deleted file mode 100644 index 5198b8d..0000000 --- a/Spider/Core/UdpServer/AsyncUDPServer.cs +++ /dev/null @@ -1,99 +0,0 @@ -using Spider.Log; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading.Tasks; - -namespace Spider.Core.UdpServer -{ - public delegate void MessageReceived(byte[] buffer, IPEndPoint endpoint); - - public class AsyncUDPServer - { - private UdpClient _server; - - private IPEndPoint endpoint; - public IPEndPoint Endpoint - { - get { return endpoint; } - } - - public bool IsRunning { get; private set; } - - public AsyncUDPServer(IPEndPoint endpoint) - { - this.endpoint = endpoint; - _server = new UdpClient(endpoint); - const uint IOC_IN = 0x80000000; - int IOC_VENDOR = 0x18000000; - int SIO_UDP_CONNRESET = (int)(IOC_IN | IOC_VENDOR | 12); - _server.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, new byte[4]); - } - - public void Start() - { - if (!IsRunning) - { - IsRunning = true; - _server.EnableBroadcast = true; - _server.BeginReceive(ReceiveDataAsync, null); - } - } - - public void Stop() - { - if (IsRunning) - { - IsRunning = false; - _server.Close(); - - } - } - - - public event MessageReceived MessageReceived; - - private void ReceiveDataAsync(IAsyncResult ar) - { - IPEndPoint remote = null; - byte[] buffer = null; - try - { - buffer = _server.EndReceive(ar, ref remote); - MessageReceived?.Invoke(buffer, remote); - if (IsRunning && _server != null) - _server.BeginReceive(ReceiveDataAsync, null); - } - catch (Exception ex) - { - Logger.Fatal(ex.ToString()); - if (IsRunning && _server != null) - _server.BeginReceive(ReceiveDataAsync, null); - - } - } - - - - /// - /// 发送数据 - /// - public void Send(byte[] buffer, IPEndPoint endpoint) - { - try - { - if (endpoint.Address != IPAddress.Any) - _server.Send(buffer, buffer.Length, endpoint); - } - catch (Exception) - { - //TODO 异常处理 - } - } - - - } -} diff --git a/Spider/Core/UdpSocketListener.cs b/Spider/Core/UdpSocketListener.cs index a49a554..c3e984b 100644 --- a/Spider/Core/UdpSocketListener.cs +++ b/Spider/Core/UdpSocketListener.cs @@ -75,9 +75,9 @@ namespace Spider.Core var errorCode = (int)e.SocketError; //The listen socket was closed - if (errorCode == 995 || errorCode == 10004 || errorCode == 10038) - //return; - Logger.Fatal($"The listen socket was closed errorCode:{errorCode}"); + //if (errorCode == 995 || errorCode == 10004 || errorCode == 10038) + //return; + //Logger.Fatal($"The listen socket was closed errorCode:{errorCode}"); Logger.Fatal($"errorCode:{errorCode}"); } @@ -88,8 +88,6 @@ namespace Spider.Core //获取接收到的数据 byte[] ByteArray = new byte[e.BytesTransferred]; Array.Copy(e.Buffer, 0, ByteArray, 0, ByteArray.Length); - //测试 - Logger.Debug($"buffer:{ByteArray.Length} remote:{(IPEndPoint)e.RemoteEndPoint}"); MessageReceived?.Invoke(ByteArray, (IPEndPoint)e.RemoteEndPoint); } catch (Exception exc) @@ -159,9 +157,7 @@ namespace Spider.Core if (endpoint.Address != IPAddress.Any) { var len = m_ListenSocket.SendTo(buffer, endpoint); - - //测试 - Logger.Warn($"Send :{len} {buffer.Length} {endpoint}"); + //Logger.Warn($"Send :{len} {buffer.Length} {endpoint}"); } else { diff --git a/Spider/Log/Logger.cs b/Spider/Log/Logger.cs index 51cf66a..d849412 100644 --- a/Spider/Log/Logger.cs +++ b/Spider/Log/Logger.cs @@ -42,9 +42,9 @@ namespace Spider.Log - public static void ConsoleWrite(string msg) + public static void ConsoleWrite(string msg, ConsoleColor consoleColor = ConsoleColor.Green) { - Console.ForegroundColor = ConsoleColor.Green; + Console.ForegroundColor = consoleColor; Console.WriteLine("------------------------------------------------------"); Console.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]{msg}"); } diff --git a/Spider/Queue/MemoryQueue.cs b/Spider/Queue/DefaultQueue.cs similarity index 92% rename from Spider/Queue/MemoryQueue.cs rename to Spider/Queue/DefaultQueue.cs index 2f10d3d..9c462aa 100644 --- a/Spider/Queue/MemoryQueue.cs +++ b/Spider/Queue/DefaultQueue.cs @@ -9,10 +9,10 @@ using Tancoder.Torrent; namespace Spider.Queue { - public class MemoryQueue : IQueue + public class DefaultQueue : IQueue { public ConcurrentQueue> _queue = null; - public MemoryQueue() + public DefaultQueue() { _queue = new ConcurrentQueue>(); } diff --git a/Spider/Queue/RedisQueue.cs b/Spider/Queue/RedisQueue.cs index b45c5c7..d0ddc9d 100644 --- a/Spider/Queue/RedisQueue.cs +++ b/Spider/Queue/RedisQueue.cs @@ -10,7 +10,7 @@ namespace Spider.Queue { public class RedisQueue : IQueue { - + //TODO public RedisQueue() { } diff --git a/Spider/Spider.csproj b/Spider/Spider.csproj index c675507..7ccad3a 100644 --- a/Spider/Spider.csproj +++ b/Spider/Spider.csproj @@ -57,9 +57,6 @@ - - - @@ -67,11 +64,13 @@ - + + + diff --git a/Spider/SpiderConfiguration.cs b/Spider/SpiderConfiguration.cs index 906e248..7ab3524 100644 --- a/Spider/SpiderConfiguration.cs +++ b/Spider/SpiderConfiguration.cs @@ -3,6 +3,7 @@ using Spider.Cache; using Spider.Core; using Spider.Log; using Spider.Queue; +using Spider.Store; using System; using System.Collections.Generic; using System.IO; @@ -28,6 +29,7 @@ namespace Spider public SpiderSetting _option { get; set; } public ICache _cache { get; set; } public IQueue _queue { get; set; } + public IStore _store { get; set; } private SpiderConfiguration(SpiderSetting option) { @@ -73,7 +75,7 @@ namespace Spider public SpiderConfiguration UseDefaultQueue() { - _builder.RegisterType().As().Named("Queue").SingleInstance(); + _builder.RegisterType().As().Named("Queue").SingleInstance(); return _instance; } @@ -85,12 +87,13 @@ namespace Spider public SpiderConfiguration UseElasticSearchStore() { + _builder.RegisterType().As().Named("Store").SingleInstance(); return _instance; } public SpiderConfiguration UseMongoDBStore() { - //TODO + _builder.RegisterType().As().Named("Store").SingleInstance(); return _instance; } @@ -110,18 +113,15 @@ namespace Spider { throw new Exception("没有注册Queue"); } + //if (!_container.IsRegisteredWithName("Store")) + //{ + // throw new Exception("没有注册Store"); + //} _queue = _container.ResolveNamed("Queue"); _cache = _container.ResolveNamed("Cache"); + //_store = _container.ResolveNamed("Store"); - Task.Run(() => - { - while (true) - { - Thread.Sleep(1000 * 60); - Logger.Info($"QueueCount:{_queue.Count()}"); - } - }); for (var i = 0; i < _option.MaxSpiderThreadCount; i++) { @@ -197,13 +197,7 @@ namespace Spider File.WriteAllBytes(filepath, metadata.Encode()); } var list = new List(); - //foreach (var item in metadata) - //{ - // list.Add($"[key]={item.Key}[val]={item.Value}"); - //} - //var str = string.Join("&", list); - //Logger.Warn($"{hash} {name} {str}"); - Logger.ConsoleWrite($"线程[{threadId}]下载完成 Name:{name} "); + Logger.ConsoleWrite($"线程[{threadId}]下载完成 Name:{name} ", ConsoleColor.Yellow); } } diff --git a/Spider/Store/ElasticSearchStore.cs b/Spider/Store/ElasticSearchStore.cs new file mode 100644 index 0000000..d43bb66 --- /dev/null +++ b/Spider/Store/ElasticSearchStore.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Spider.Store +{ + public class ElasticSearchStore : IStore + { + //TODO + public bool Insert(object obj) + { + throw new NotImplementedException(); + } + } +} diff --git a/Spider/Store/IStore.cs b/Spider/Store/IStore.cs index c800880..7973210 100644 --- a/Spider/Store/IStore.cs +++ b/Spider/Store/IStore.cs @@ -5,7 +5,8 @@ using System.Text; namespace Spider.Store { - interface IStore + public interface IStore { + bool Insert(object obj); } } diff --git a/Spider/Store/MongoDBStore.cs b/Spider/Store/MongoDBStore.cs new file mode 100644 index 0000000..037729d --- /dev/null +++ b/Spider/Store/MongoDBStore.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Spider.Store +{ + public class MongoDBStore : IStore + { + //TODO + public bool Insert(object obj) + { + throw new NotImplementedException(); + } + } +}